Data Exploration and Wrangling
Our goal in this section is to adjust or “wrangle” the data from each year into a common format so that we can combine the data sets across years for our analysis, and so that we have values in our variables that are correct and easy to interpret. We will need to understand what is the same and what is different across the data from different years, rename and recode the variables (e.g., by replacing the numbers 1 and 2 with the values “Male” and “Female” for the Sex variable), and combine the data. We will walk through these steps below.
First, let’s take a look at our data. We can get a good sense of it using the glimpse() function of the dplyr package.
Rows: 17,711
Columns: 29
$ psu <chr> "015438", "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "B…
$ Qn1 <dbl> 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,…
$ Qn2 <dbl> 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2…
$ Qn3 <dbl> 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5…
$ ECIGT <dbl> 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1…
$ ECIGAR <dbl> 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2…
$ ESLT <dbl> 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EELCIGT <dbl> 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1…
$ EROLLCIGTS <dbl> 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2…
$ EFLAVCIGTS <dbl> 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EBIDIS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EFLAVCIGAR <dbl> 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2…
$ EHOOKAH <dbl> 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EPIPE <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ ESNUS <dbl> 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ EDISSOLV <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CCIGT <dbl> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CCIGAR <dbl> 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CSLT <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CELCIGT <dbl> 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CROLLCIGTS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CFLAVCIGTS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CBIDIS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CHOOKAH <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CPIPE <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CSNUS <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ CDISSOLV <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
Updating the set of variables and their names
The easiest way of making it so that the data from the different years can be combined is by making sure that the same type of data in different datasets share the same names. In addition, giving the columns informative names will help make our code more readable. Currently, it isn’t very clear what most of the variables indicate since the variable names are uninformative on their own, without the codebook.
We want to rename variables like Qn1 to something more meaningful like Age.
To do this we will use the rename() function of the dplyr package. The new name is always listed first before the =. This function will replace the old variable names with the new ones, i.e., after running the code below, there will no longer be a Qn1 variable in the data set, but there will be an Age variable instead. We will start working with the 2015 data, and then move on to the other years down below.
Ultimately we will be combining the data from each year using the bind_rows() function of the dplyr package, which will fill in NA values for any columns that do not exist for one of the years.
The data for 2016-2018 have many common attributes, so we will want to write code that can be applied to all three data sets. To do this, we will use a function in R, which is basically a piece of code that can be applied to similar but different objects in R (e.g., the data tibbles from each of these three years). Recall that you are using functions from packages all the time, like the rename() function of the dplyr package. Now you are going to write your own function! For more information on functions, see here.
These next 3 years have the same structure for many of the questions we are interested in. For example, they all have flavor questions, but not a brand question. Moreover, their variable names are consistent across the years; for each year, we want to replace the vague question name Q50A with the value menthol in all three data sets, and the same is true for the other flavor variables.
Since we want to perform the same modifications on the data from all three years, rather than repeating the same somewhat messy piece of code three times, we can do this more efficiently if we create a function to do all of these steps at once. Then we can use the map_at() function of the purrr package, which is an extension of the map() function that we used in the [Reading in the excel files] section to apply the function we just created (for renaming variables etc.) specifically to the data from 2016-2018 within the nyts_data. By using vars() inside of the map_at() function we can specify what tibbles within our nyts_data list we want to include or exclude.
So how do you create a function? You first need to specify that you are creating a function by using the function() base function. Yes, that’s right it as a function for creating functions called function!
First we specify our input within the parentheses of function(). Thus if our function will apply something to an input called x then we would use function(x). Really our input can be named whatever we want, but we we need to refer to it consistently within our function to indicate what we want done with the input data. We can actually have more than one input as well, we would indicate two inputs like this: function(x, b). Here we we would be using both x and b to do something in our function.
The next part of a function is within defined within curly brackets {}. This is where we write what we want done to our inputs.
Click here to see a simple example
Our function will be called simple_function and it will take the input x. It will add 2 to our input.
[1] 1 2 3 4
[1] 3 4 5 6
The name of our input does not need to match like in the above example. Instead we can use an input that is a vector called y, and we can rewrite our function to use a more informative input argument like vector_data. Now we specify using the argument vector_data = to indicate that y is our input that we want to perform the function on.
[1] 3 4 5 6
In our case we will be applying our function to the variable names for the dataset for each year. Thus our x is the dataset for each year. The output of our function is the result of renaming these variables for each year.
Update_survey <- function(x) { x %>%
rename(Age = Q1,
Sex = Q2,
Grade = Q3,
menthol = Q50A,
clove_spice = Q50B,
fruit = Q50C,
chocolate = Q50D,
alcoholic_drink = Q50E,
candy_dessert_sweets = Q50F,
other = Q50G)
}
# options to apply the function to the data:
# nyts_data <-nyts_data %>% map_at(vars(nyts2016, nyts2017, nyts2018), Update_survey)
nyts_data <- nyts_data %>% map_at(vars(-nyts2015, -nyts2019), Update_survey)
The final year, 2019, has a slightly different data structure compared to these earlier data sets. It actually has a brand_ecig variable already and different question numbers correspond to our flavor questions of interest. So we will rename the variables in this data set individually. We could also write this as a function, but since we are only applying this one time, there is no need to. Functions are really helpful for repeating the same task repeatedly using different data inputs.
nyts_data[["nyts2019"]] <- nyts_data[["nyts2019"]] %>%
rename(brand_ecig = Q40,
Age = Q1,
Sex = Q2,
Grade = Q3,
menthol = Q62A,
clove_spice = Q62B,
fruit = Q62C,
chocolate = Q62D,
alcoholic_drink = Q62E,
candy_dessert_sweets = Q62F,
other = Q62G)
Now let’s take a look at the variable names for each of the years using the map function from purrr.
It’s looking better! The data that overlap across years have the same variable names.
Updating Values
Now that we have made some progress on the selection and names of the variables themselves, we will work on the values contained in the different variables.
We can start with updating the values for Age and Grade, so that they are more understandable.
Recall from the codebook for this year’s data set that Age isn’t listed in the way one might expect, i.e., it is not just a number of years, but a numerically valued categorical variable.

The same is true for Grade:

This is why it is so important to always check the codebook!!
We also want to replace the value of 19 for Age to be ">18" and the value of 13 for Grade to be replaced with "Ungraded/Other" Also according to the codebooks, numeric values of 1 indicate a survey answer of FALSE, while a value of 2 indicates TRUE. Sex also needs to be recoded. If we take a look at the code books carefully (make sure you look at the questions that we pulled, not the recoded values), we will see that males are indicated by 1 and females are indicated by 2. Finally some values are indicated with "*" or"**" when they are missing. We want to replace these with NA.
Let’s create a function to make all these updates. We will use the mutate function of the dplyr package to modify these variables. This function can also be used to create new variables. We will also use the recode() function of the dplyr package to replace specific values of certain variables.
Update_values <- function(x) { x %>%
mutate(Age = as.numeric(Age) + 8,
Grade = as.numeric(Grade) + 5) %>%
mutate(Age = as.factor(Age),
Grade = as.factor(Grade),
Sex = as.factor(Sex)) %>%
mutate(Sex = recode(Sex,
`1` = "male",
`2` = "female")
) %>%
mutate_all(~ replace(., . %in% c("*", "**"), NA)) %>%
mutate(Age = recode(Age,
`19` = ">18"),
Grade = recode(Grade,
`13` = "Ungraded/Other")) %>%
mutate_at(vars(starts_with("E", ignore.case = FALSE),
starts_with("C", ignore.case = FALSE)),
list(~ recode(.,
`1` = TRUE,
`2` = FALSE,
.default = NA,
.missing = NA)))
}
nyts_data <- nyts_data %>% map(., Update_values)
Now if we wanted to check that everything is expected we could do something like this to check the Sex variable using the count() function of the dplyr package. It is advisable to check your data frequently to make sure that it is as expected!
According to the codebook, we should have:
1) 8,958 males in 2015 2) 10,438 males in 2016 3) 8,881 males in 2017
4) 10,069 males in 2018
5) 9,803 males in 2019
$nyts2015
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 8958
2 female 8622
3 <NA> 131
$nyts2016
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 10438
2 female 10082
3 <NA> 155
$nyts2017
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 8881
2 female 8815
3 <NA> 176
$nyts2018
# A tibble: 3 x 2
Sex n
<fct> <int>
1 male 10069
2 female 9920
3 <NA> 200
$nyts2019
# A tibble: 3 x 2
Sex n
<fct> <int>
1 .N 116
2 male 9803
3 female 9099
Looks good!
The years (2016-2019) that have flavors also need the flavor data to be logical (meaning TRUE or FALSE):
In this case we also are setting missing values to FALSE because then it the TRUE values will represent those who reported using a specific flavor out of all users, rather than those that used a specific flavor compared to those who used a different flavor.
Now there are just a few changes needed that are specific to 2019. Specifically, some of the 2019 questions use the values “.N”, “.S”, and “.Z” to indicate different types of missing data (see for example Q2 of the 2019 codebook); we just want them to be replaced with NA values.
nyts_data[["nyts2019"]] <- nyts_data[["nyts2019"]] %>%
mutate_all(~ replace(., . %in% c(".N", ".S", ".Z"), NA)) %>%
mutate(psu = as.character(psu)) %>%
mutate(brand_ecig = recode(brand_ecig,
`1` = "Other", # levels 1,8 combined to `Other`
`2` = "Blu",
`3` = "JUUL",
`4` = "Logic",
`5` = "MarkTen",
`6` = "NJOY",
`7` = "Vuse",
`8` = "Other"))
Great! Now our values don’t need to be handled any differently for any of the years, thus we can combine the data across years.
Even though we have different numbers of variables for each year, we can coerce the data to be combined into one tibble by using the bind_rows() function of dplyr. Importantly, this function does not require that the columns be the same. This will create NA values for any variable that is not present in given data frame but is present in one of the other data frames that is being combined. Note that the bind_cols() function does expect that the rows match. The .id argument will create a new variable with values to link each row to its original data frame. For more information see here.
Rows: 95,465
Columns: 40
$ year <chr> "nyts2015", "nyts2015", "nyts2015", "nyts2015", …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
We will want to do some of our analysis split by year, so we would like to be sure we have one variable that has the correct value for year. It looks like we just need to remove "nyts" from the year variable that we created from the names of the tibbles in our list and we should be all set. We will use another function from the stringr package to do this. The str_remove() function takes a string followed by a pattern and removes the pattern from the string.
Here is our clean and wrangled data:
Rows: 95,465
Columns: 40
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
Note that there are several variables where there are similar names, but with a C compared to an E in the variable name. Those starting with C are related to questions about current usage (last 30 days), while those with an E are related to usage across the student respondent’s whole life (“ever” usage). We will discuss these groups further below.
Variable Table
Click here to see a table about the final variables in our data set.
value 1 = yes, value 2 = no
| year |
the year that the survey results from a particular student respondent were acquired |
| psu |
the primary sampling unit for the survey weighting |
| finwgt |
the final analysis weight for the survey weighting |
| stratum |
the stratum used for variance estimation for the survey weighting |
| Age |
the age of the student when they took the survey |
| Sex |
the sex of the student when they took the survey |
| Grade |
the grade of the the student when the took the survey |
| ECIGT |
student reported having ever tried cigarette smoking, even one or two puffs |
| ECIGAR |
student reported having ever tried cigar, cigarillo, or little cigar smoking, even one or two puffs |
| ESLT |
student reported having ever tried chewing tobacco, snuff, or dip |
| EELCIGT |
student reported having ever tried e-cigarettes |
| EROLLCIGTS |
student reported having ever tried roll-your-own cigarettes |
| EFLAVCIGTS |
(2015 only) based on answer to “Which of the following tobacco products that you used in the past 30 days were flavored?” |
| EBIDIS |
student reported having ever tried bidis (small brown cigarettes wrapped in a leaf) |
| EFLAVCIGAR |
student reported having ever tried a flavored cigar (2015-2016) |
| EHOOKAH |
student reported having ever smoked tobacco from a hookah or a waterpipe |
| EPIPE |
student reported having ever smoked tobacco from a pipe (not hookah) |
| ESNUS |
student reported having ever used snus, such as Camel or Malboro Snus |
| EDISSOLV |
student reported having ever tried dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips |
| CCIGT |
student reported they smoked cigarettes on >= 1 of the past 30 days |
| CCIGAR |
student reported they smoked cigars on >= 1 of the past 30 days |
| CSLT |
student reported they used chewing tobacco, snuff, or dip on >= 1 of the past 30 days |
| CELCIGT |
student reported they used electronic cigarettes or e-cigarettes one or more days in the past 30 |
| CROLLCIGTS |
student reported they smoked roll-your-own cigarettes during the past 30 days |
| CFLAVCIGTS |
(2015 only) based on answer to “Which of the following tobacco products that you used in the past 30 days were flavored?” |
| CBIDIS |
student reported they smoked bidis during the past 30 days |
| CHOOKAH |
student reported they smoked tobacco in a hookah on >= 1 of the past 30 days |
| CPIPE |
student reported they smoked tobacco in a pipe (not hookah) during the past 30 days |
| CSNUS |
student reported they used snus during the past 30 days |
| CDISSOLV |
student reported they used dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips during the past 30 days |
| brand_ecig |
student answer to “During the past 30 days, what brand of e-cigarettes did you usually use?” |
| menthol |
student selected Menthol or mint as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| clove_spice |
student selected clove or spice as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| fruit |
student selected fruit as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| chocolate |
student selected chocolate as the answer to “What flavors of tobacco products have you used in the past 30 days? (select one or more)” |
| alcoholic_drink |
student selected alcoholic drink (such as wine, cognac, margarita, or other cocktails) as the answer to “What flavors of tobacco products have you used in the past 30 days? (choose one or more)” |
| candy_dessert_sweets |
student selected candy, desserts or other sweets as the answer to “What flavors of tobacco products have you used in the past 30 days? (choose one or more)” |
| other |
student selected some other flavor not listed as the answer to “What flavors of tobacco products have you used in the past 30 days? (choose one or more)” |
| EHTP |
student reported having ever tried heated (also known as “heat-not-burn”) tobacco products |
| CHTP |
student reported they used heated tobacco products during the past 30 days |
Data Visualization
Recall that our main questions were:
- How has tobacco and e-cigarette/vaping use by American youths changed since 2015?
- How does e-cigarette use compare between males and females?
What vaping brands and flavors appear to be used the most frequently?
We will base this on the following survey questions:
> “During the past 30 days, what brand of e-cigarettes did you usually use?”
>" What flavors of tobacco products have you used in the past 30 days?"
Is there a relationship between e-cigarette/vaping use and other tobacco use?
We are now going to create data visualizations to explore each of these questions.
For many of these questions we will be interested in both current and ever users, so we will want to create a variable for labeling individuals who are current users of any tobacco product (or not, i.e., who do not currently use a tobacco product) and a variable for labeling individuals who are “ever users” of any tobacco product (or not, i.e., who have never used a tobacco product).
We define these two groups as follows:
- current = students who used a product for >=1 day in the past 30 days
- ever = students who report having used or tried a product at any point in time
All current users are therefore ever users but not all ever users are current users. Thus, current users are a subset of ever users.
To add these grouping variables to our data we will do a bit more wrangling using the mutate() function again of the dplyr package. As discussed above, our data set contains a set of questions that relate to whether the student has ever used the particular tobacco product (questions that start with the letter “E”), and questions that relate to whether the student currently uses the particular tobacco product (questions that start with the letter “C”).
Here are some examples for these data entries:
- EPIPE: Students who reported they have smoked tobacco from a pipe (not hookah).
- CPIPE: Students who reported they smoked tobacco in a pipe (not hookah) during the past 30 days.
- EROLLCIGTS: RECODE: Students who reported they have tried smoking roll-your-own cigarettes.
- CROLLCIGTS: RECODE: Students who reported they smoked roll-your-own cigarettes during the past 30 days.
Based on many questions like this:
In the past 30 days, which of the following products have you used on at least one day? (Select one or more) A. Roll-your-own cigarettes
B. Pipes filled with tobacco (not hookah or waterpipe)
C. Snus, such as Camel, Marlboro, or General Snus
D. Dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips
E. Bidis (small brown cigarettes wrapped in a leaf)
F. I have not used any of the products listed above in the past 30 days
Which of the following tobacco products have you ever tried, even just one time? (Select one or more)
A. Roll-your-own cigarettes
B. Pipes filled with tobacco (not hookah or waterpipe)
C. Snus, such as Camel, Marlboro, or General Snus
D. Dissolvable tobacco products such as Ariva, Stonewall, Camel orbs, Camel sticks, Marlboro sticks, or Camel strips
E. Bidis (small brown cigarettes wrapped in a leaf)
F. I have never tried any of the products listed above
We will sum across the variables that relate to ever or current tobacco usage questions to determine if the student answered yes to any of the ever or current questions. To do this we will use the base rowSums function.
We will then use the case_when() function of the dplyr package to convert the sum values to TRUE or FALSE based on the threshold of zero. If the sum is greater than zero, then we know the student answered yes to at least one question.
nyts_data %<>%
mutate(tobacco_sum_ever = rowSums(select(., starts_with("E",
ignore.case = FALSE)), na.rm = TRUE),
tobacco_sum_current = rowSums(select(., starts_with("C",
ignore.case = FALSE)), na.rm = TRUE)) %>%
mutate(tobacco_ever = case_when(tobacco_sum_ever > 0 ~ TRUE,
tobacco_sum_ever == 0 ~ FALSE),
tobacco_current = case_when(tobacco_sum_current > 0 ~ TRUE,
tobacco_sum_current == 0 ~ FALSE))
Rows: 95,465
Columns: 44
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ tobacco_sum_ever <dbl> 1, 4, 0, 3, 0, 2, 8, 4, 0, 0, 0, 1, 1, 0, 0, 4, …
$ tobacco_sum_current <dbl> 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ tobacco_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE…
$ tobacco_current <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, F…
We are also interested in e-cigarette/vaping product usage compared to other tobacco products, so we will create some variables related to the sum of all e-cigarette usage question variables and the sum of all tobacco usage question variables excluding those that are about e-cigarettes. There is only one variable about e-cigarette usage ever (EELCIGT) and one about current usage (CELCIGT).
nyts_data <- nyts_data %>%
mutate(ecig_sum_ever = rowSums(select(., EELCIGT), na.rm = TRUE),
ecig_sum_current = rowSums(select(., CELCIGT), na.rm = TRUE),
non_ecig_sum_ever = rowSums(select(., starts_with("E",
ignore.case = FALSE),
-EELCIGT), na.rm = TRUE),
non_ecig_sum_current = rowSums(select(., starts_with("C",
ignore.case = FALSE),
-CELCIGT), na.rm = TRUE)) %>%
mutate(ecig_ever = case_when(ecig_sum_ever > 0 ~ TRUE,
ecig_sum_ever == 0 ~ FALSE),
ecig_current = case_when(ecig_sum_current > 0 ~ TRUE,
ecig_sum_current == 0 ~ FALSE),
non_ecig_ever = case_when(non_ecig_sum_ever > 0 ~ TRUE,
non_ecig_sum_ever == 0 ~ FALSE),
non_ecig_current = case_when(non_ecig_sum_current > 0 ~ TRUE,
non_ecig_sum_current == 0 ~ FALSE))
Rows: 95,465
Columns: 52
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, …
$ psu <chr> "015438", "015438", "015438", "015438", "015438"…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.8745…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3",…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, …
$ Sex <fct> female, male, male, male, female, female, male, …
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FA…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, F…
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ tobacco_sum_ever <dbl> 1, 4, 0, 3, 0, 2, 8, 4, 0, 0, 0, 1, 1, 0, 0, 4, …
$ tobacco_sum_current <dbl> 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ tobacco_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE…
$ tobacco_current <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, F…
$ ecig_sum_ever <dbl> 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, …
$ ecig_sum_current <dbl> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ non_ecig_sum_ever <dbl> 1, 3, 0, 2, 0, 1, 7, 3, 0, 0, 0, 0, 1, 0, 0, 3, …
$ non_ecig_sum_current <dbl> 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ ecig_ever <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ ecig_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ non_ecig_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE…
$ non_ecig_current <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, …
Finally, we are also interested in grouping students that only use e-cigarettes and those that only use other forms of tobacco.
Recall that current users are a subset of ever users, thus students would typically answer yes to having tried vaping products if they had used them one or more days in the past 30 days.
First we will make a small toy dataset called test to show what we will do with the larger dataset:
test <- tibble(ecig_ever = c("TRUE", "TRUE", "TRUE", "TRUE", "FALSE",
"FALSE", "TRUE", "FALSE", "FALSE"),
non_ecig_ever = c("TRUE", "FALSE", "FALSE", "FALSE", "FALSE",
"FALSE", "TRUE", "TRUE", "TRUE"),
ecig_current = c("TRUE", "FALSE", "FALSE", "TRUE", "TRUE",
"FALSE", "FALSE", "FALSE", "FALSE"),
non_ecig_current = c("TRUE", "FALSE", "TRUE", "FALSE", "TRUE",
"FALSE", "FALSE", "FALSE", "TRUE"))
test
# A tibble: 9 x 4
ecig_ever non_ecig_ever ecig_current non_ecig_current
<chr> <chr> <chr> <chr>
1 TRUE TRUE TRUE TRUE
2 TRUE FALSE FALSE FALSE
3 TRUE FALSE FALSE TRUE
4 TRUE FALSE TRUE FALSE
5 FALSE FALSE TRUE TRUE
6 FALSE FALSE FALSE FALSE
7 TRUE TRUE FALSE FALSE
8 FALSE TRUE FALSE FALSE
9 FALSE TRUE FALSE TRUE
Now, let’s look at identifying students who have tried e-cigarettes, but are not current users, and who have never tried other tobacco products (and are therefore not current users). We will again use the case_when() and the mutate function to create new variables with specific values when certain conditions are met. In this case, we will specify that several conditions must be met by using the & symbol. For a value of TRUE for the new ecig_only_ever variable, all of the conditions combined with & must be met. If any of the conditions are not met then the ecig_only_ever value will be FALSE based on the last line TRUE ~ FALSE.
# A tibble: 9 x 5
ecig_ever non_ecig_ever ecig_current non_ecig_current ecig_only_ever
<chr> <chr> <chr> <chr> <lgl>
1 TRUE TRUE TRUE TRUE FALSE
2 TRUE FALSE FALSE FALSE TRUE
3 TRUE FALSE FALSE TRUE FALSE
4 TRUE FALSE TRUE FALSE FALSE
5 FALSE FALSE TRUE TRUE FALSE
6 FALSE FALSE FALSE FALSE FALSE
7 TRUE TRUE FALSE FALSE FALSE
8 FALSE TRUE FALSE FALSE FALSE
9 FALSE TRUE FALSE TRUE FALSE
We can see from the second row, that the ecig_only_ever is TRUE when we would expect it to be. We can also see from the fourth row, that even though the student reported yes to ever trying e-cigarettes, because they also reported yes to currently using e-cigarettes the value for only ever trying e-cigarettes is FALSE. Additionally we can see from the seventh row that similarly even though the student reported yest to ever trying e-cigarettes, they also reported yes to ever trying other products, and the value for only ever trying e-cigarettes is FALSE. Importantly, we can see from the 6th row, that if all responses are negative than the value is FALSE.
Now we will expand this to the other possible categories. In this case we note that since current users are a subset of ever users, it doesn’t matter if a user reports yes to ever trying e-cigarettes, they can still be a current user.
Rows: 9
Columns: 9
$ ecig_ever <chr> "TRUE", "TRUE", "TRUE", "TRUE", "FALSE", "FALSE…
$ non_ecig_ever <chr> "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FA…
$ ecig_current <chr> "TRUE", "FALSE", "FALSE", "TRUE", "TRUE", "FALS…
$ non_ecig_current <chr> "TRUE", "FALSE", "TRUE", "FALSE", "TRUE", "FALS…
$ ecig_only_ever <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ecig_only_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ non_ecig_only_ever <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ non_ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ no_use <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,…
Take a minute to check that the values are what we would expect.
OK, now we are going to make a Group variable based on the new variables we just made to classify students into one of four mutually exclusive and exhaustive categories. In this case we will have a particular value based on one condition or another. This or conditional is specified by the | symbol. Only one of the conditions needs to exist for that particular value, whereas when we used the & symbol, all of the conditions had to be met.
If a student has ever tried or currently uses e-cigarettes, but has never tried other tobacco products, the value will be Only e-cigarettes. If a student has ever tried or is a current user of other tobacco products, but has never tried e-cigarettes, the value will be Only other products. If the value of the no_use variable is simply TRUE, then the Group variable value will be Neither. Finally, if a student has tried or currently uses both e-cigarettes and other tobacco products the Group variable value will be Combination of products. Thus in this case the values for the usage of the variables based on only using e-cigarettes or only other products will all be FALSE.
# A tibble: 4 x 2
Group n
<chr> <int>
1 Combination of products 4
2 Neither 1
3 Only e-cigarettes 2
4 Only other products 2
Rows: 9
Columns: 10
$ ecig_ever <chr> "TRUE", "TRUE", "TRUE", "TRUE", "FALSE", "FALSE…
$ non_ecig_ever <chr> "TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "FA…
$ ecig_current <chr> "TRUE", "FALSE", "FALSE", "TRUE", "TRUE", "FALS…
$ non_ecig_current <chr> "TRUE", "FALSE", "TRUE", "FALSE", "TRUE", "FALS…
$ ecig_only_ever <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ecig_only_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ non_ecig_only_ever <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ non_ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ no_use <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,…
$ Group <chr> "Combination of products", "Only e-cigarettes",…
OK, now that we have seen how this works with our toy dataset, we will apply our code to our nyts_data.
nyts_data %<>%
mutate(ecig_only_ever = case_when(ecig_ever == TRUE &
non_ecig_ever == FALSE &
ecig_current == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
ecig_only_current = case_when(ecig_current == TRUE &
non_ecig_ever == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
non_ecig_only_ever = case_when(non_ecig_ever == TRUE &
ecig_ever == FALSE &
ecig_current == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
non_ecig_only_current = case_when(non_ecig_current == TRUE &
ecig_ever == FALSE &
ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE),
no_use = case_when(non_ecig_ever == FALSE &
ecig_ever == FALSE &
ecig_current == FALSE &
non_ecig_current == FALSE ~ TRUE,
TRUE ~ FALSE)) %>%
mutate(Group = case_when(ecig_only_ever == TRUE |
ecig_only_current == TRUE ~ "Only e-cigarettes",
non_ecig_only_ever == TRUE |
non_ecig_only_current == TRUE ~ "Only other products",
no_use == TRUE ~ "Neither",
ecig_only_ever == FALSE &
ecig_only_current == FALSE &
non_ecig_only_ever == FALSE &
non_ecig_only_current == FALSE &
no_use == FALSE ~ "Combination of products"))
Lastly, it can be very helpful to have the total number of students surveyed each year. We can easily add a variable for this by using the add_count() function of the dplyr package. This will create a variable called n which will show the total number of survey responses for that year.
Rows: 95,465
Columns: 59
$ year <dbl> 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015,…
$ psu <chr> "015438", "015438", "015438", "015438", "015438…
$ finwgt <dbl> 216.7268, 324.9620, 324.9620, 397.1552, 264.874…
$ stratum <chr> "BR3", "BR3", "BR3", "BR3", "BR3", "BR3", "BR3"…
$ Age <fct> 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,…
$ Sex <fct> female, male, male, male, female, female, male,…
$ Grade <fct> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,…
$ ECIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TR…
$ ECIGAR <lgl> TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, F…
$ ESLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,…
$ EELCIGT <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TR…
$ EROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,…
$ EFLAVCIGTS <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, …
$ EBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ EFLAVCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, …
$ EHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ EPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ ESNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,…
$ EDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CCIGT <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CCIGAR <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ CSLT <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CELCIGT <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ CROLLCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CFLAVCIGTS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CBIDIS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CHOOKAH <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CPIPE <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CSNUS <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ CDISSOLV <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ menthol <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ clove_spice <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ fruit <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ chocolate <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ alcoholic_drink <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ candy_dessert_sweets <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ other <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ EHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ CHTP <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ brand_ecig <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ tobacco_sum_ever <dbl> 1, 4, 0, 3, 0, 2, 8, 4, 0, 0, 0, 1, 1, 0, 0, 4,…
$ tobacco_sum_current <dbl> 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ tobacco_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ tobacco_current <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, …
$ ecig_sum_ever <dbl> 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,…
$ ecig_sum_current <dbl> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ non_ecig_sum_ever <dbl> 1, 3, 0, 2, 0, 1, 7, 3, 0, 0, 0, 0, 1, 0, 0, 3,…
$ non_ecig_sum_current <dbl> 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ ecig_ever <lgl> FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TR…
$ ecig_current <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,…
$ non_ecig_ever <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRU…
$ non_ecig_current <lgl> FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ ecig_only_ever <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ non_ecig_only_ever <lgl> TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,…
$ non_ecig_only_current <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ no_use <lgl> FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, …
$ Group <chr> "Only other products", "Combination of products…
$ n <int> 17711, 17711, 17711, 17711, 17711, 17711, 17711…
Question 1
Recall that we are interested in investigating how vaping product use has compared with other tobacco use over time. To answer this, we first want to get a sense of how tobacco use has changed in general since 2015.
To create a visualization of how tobacco usage has changed over time, we will first convert the usage data to a percent value for each year, telling us what percent of student respondents fall into a particular usage category. To do this we will use the group_by() and summarize() functions of the dplyr package. This will create new variables which we will name Ever and Current based on the percentages of TRUE values for tobacco_ever and tobacco_current for each year. In this case the mean() function is used to calculate the percentages based on an automatic conversion that R does where for TRUE/FALSE variables, TRUE is given a value of one and FALSE is given a value of zero. The mean of a 0-1 binary variable is just the percent of the time the value is 1. NA values do not contribute to the total count when we include the argument na.rm = TRUE to our function call.
Click here to see a toy example:
# A tibble: 10 x 1
var1
<lgl>
1 TRUE
2 TRUE
3 TRUE
4 FALSE
5 FALSE
6 FALSE
7 FALSE
8 FALSE
9 FALSE
10 FALSE
# A tibble: 1 x 1
Percentage
<dbl>
1 30
# A tibble: 10 x 1
var1
<lgl>
1 TRUE
2 TRUE
3 TRUE
4 FALSE
5 FALSE
6 FALSE
7 NA
8 NA
9 NA
10 NA
# A tibble: 1 x 1
Percentage
<dbl>
1 50
And now back to our data:
# A tibble: 5 x 3
year Ever Current
<dbl> <dbl> <dbl>
1 2015 36.8 18.0
2 2016 33.4 14.0
3 2017 31.8 14.4
4 2018 34.7 18.7
5 2019 39.7 22.4
We will use the pivot_longer function to take all columns except year (in this case the Ever and Current columns), to create a column called User that will contain the current column name information and a column called Percentage of students which will contain the mean percentage values that we just calculated. This converts our data into a format called “long” format.
# A tibble: 10 x 3
year User `Percentage of students`
<dbl> <chr> <dbl>
1 2015 Ever 36.8
2 2015 Current 18.0
3 2016 Ever 33.4
4 2016 Current 14.0
5 2017 Ever 31.8
6 2017 Current 14.4
7 2018 Ever 34.7
8 2018 Current 18.7
9 2019 Ever 39.7
10 2019 Current 22.4
You may have noticed that our data is longer than it used to be! Hence the name of the function pivot_longer(). Data is often easier to plot when it is in this format.
Now we will use this data to create a plot using the ggplot2 package.
The first thing we do to create a plot is specify what data we are using for our x axis and y axis with theaes() argument of the ggplot() function. Then we add layers to our plot that specify what type of plot we would like to create. We can use the geom_line() function to create lines for each type of user. We specify that we want to use different line types for each user using aes(). We will also add points to our lines using the geom_point() function. We can add additional layers to specify colors and details about labels and legends etc.
plot1 <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize(Ever = (mean(tobacco_ever, na.rm = TRUE) * 100),
Current = (mean(tobacco_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students") %>%
ggplot(aes(x = year, y = `Percentage of students`)) +
geom_line(aes(linetype = User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2, 1)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0, 70, by = 10),
labels = seq(0, 70, by = 10),
limits = c(0, 70)) +
# this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has tobacco use varied over the years?",
y = "% of students")
plot1

Nice! Now we can see how overall tobacco usage has changed since 2017. It appears that usage first decreased from 2015 to 2017 and then increased a bit since 2017, surpassing the levels in 2015.
What about e-cigarette use? How has the usage of e-cigarettes changed over time?
plot1a <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize(Ever = (mean(ecig_ever, na.rm = TRUE) * 100),
Current = (mean(ecig_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = -year, names_to = "User", values_to = "Percentage of students") %>%
ggplot(aes(x = year, y = `Percentage of students`)) +
geom_line(aes(linetype = User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2, 1)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0, 60, by = 10),
labels = seq(0, 60, by = 10),
limits = c(0, 60)) +
# this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has e-cigarette use varied over the years?",
y = "% of students")
plot1a
It looks like the shape of the plot is very similar to tobacco usage overall. We see a downward trend until 2017 when the rate of both current and ever users increased. Recall that this is in agreement with the articles that we referenced earlier. We can see that the slope looks steeper for e-cigarette usage as compared to all tobacco products (including e-cigarettes).
Now let’s plot this data together on the same plot.
We will have four groups (e-cigarette ever users, e-cigarette current users, tobacco ever users, and tobacco current users) to plot, therefore, it would be useful to add color to our plot. Keep in mind that e-cigarette users are a subset of any tobacco product users.
One important thing to keep in mind when creating plots is that individuals with color blindness may have a difficult time distinguishing groups when certain color choices are used.
One great option is to use the viridis package, which offers color palettes with colors that are still distinguishable by individuals with most forms of color blindness.
We can choose which colors we want to use by using the show_col() function of the scales package.
Here are some color options:

We will select the first and fourth colors for our plot. To add these specific colors we will use the scale_color_manual() function of the ggplot2 package.
We will calculate the mean ever and current usage percentages for students who used e-cigarettes or any tobacco products (including e-cigarettes) for each year again using the group_by() and summarize() functions. We will again use the pivot_longer function to convert our data to long format. We will also use the separate() function of the tidyr package to create two variables from one of the variables. This is done by separating by, in this case, an underscore.
nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_Any Tobacco Product \n (including e-cigarettes)" =
(mean(tobacco_ever, na.rm = TRUE) * 100),
"Current_Any Tobacco Product \n (including e-cigarettes)" =
(mean(tobacco_current, na.rm = TRUE) * 100),
"Ever_E-cigarettes" =
(mean(ecig_ever, na.rm = TRUE) * 100),
"Current_E-cigarettes" =
(mean(ecig_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = -year,
names_to = "User",
values_to = "Percentage of students") %>%
separate(User, into = c("User", "Product"), sep = "_") %>%
head()
# A tibble: 6 x 4
year User Product `Percentage of studen…
<dbl> <chr> <chr> <dbl>
1 2015 Ever "Any Tobacco Product \n (including e-cig… 36.8
2 2015 Current "Any Tobacco Product \n (including e-cig… 18.0
3 2015 Ever "E-cigarettes" 26.4
4 2015 Current "E-cigarettes" 11.0
5 2016 Ever "Any Tobacco Product \n (including e-cig… 33.4
6 2016 Current "Any Tobacco Product \n (including e-cig… 14.0
plot1t <- nyts_data %>%
group_by(year) %>%
summarize("Ever_Any Tobacco Product \n (including e-cigarettes)" =
(mean(tobacco_ever, na.rm = TRUE) * 100),
"Current_Any Tobacco Product \n (including e-cigarettes)" =
(mean(tobacco_current, na.rm = TRUE) * 100),
"Ever_E-cigarettes" =
(mean(ecig_ever, na.rm = TRUE) * 100),
"Current_E-cigarettes" =
(mean(ecig_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = -year,
names_to = "User",
values_to = "Percentage of students") %>%
separate(User,
into = c("User", "Product"),
sep = "_") %>%
ggplot(aes(x = year,
y = `Percentage of students`,
color = Product)) +
geom_line(aes(linetype = User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2, 1)) +
# we want purple associated with e-cigarettes to be consistent with later plots
scale_color_manual(values = rev(v_colors)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0, 60, by = 10),
labels = seq(0, 60, by = 10),
limits = c(0, 60)) +
# this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How has tobacco use varied over the years?",
y = "% of students")
plot1t

We see an increase in all categories starting in 2017, but the rate of increase is higher for students using only e-cigarettes (current or ever users), as shown by the higher slope of the e-cigarette lines.
In the above plots, the “Any tobacco product” groups include individuals in the “E-cigarette only” groups. Now let’s plot students in two mutually exclusive groups on the same plot: those who reported either using only e-cigarettes or only other tobacco products (besides e-cigarettes), but not both.
We will calculate the mean ever and current usage percentages for students in these two mutually exclusive groups, again using the group_by() function and the summarize() function. We will again use the pivot_longer function to convert our data to long format. We will also again use the separate() function of the tidyr package to create two variables from one variable. This is done by separating by, in this case, a space.
nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_E-cigarette" =
(mean(ecig_only_ever, na.rm = TRUE) * 100),
"Current_E-cigarette" =
(mean(ecig_only_current, na.rm = TRUE) * 100),
"Ever_Non-e-cigarette" =
(mean(non_ecig_only_ever, na.rm = TRUE) * 100),
"Current_Non-e-cigarette" =
(mean(non_ecig_only_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = -year,
names_to = "User",
values_to = "Percentage of students") %>%
tidyr::separate(User, into = c("User", "Product"), sep = "_") %>%
head()
# A tibble: 6 x 4
year User Product `Percentage of students`
<dbl> <chr> <chr> <dbl>
1 2015 Ever E-cigarette 4.36
2 2015 Current E-cigarette 1.54
3 2015 Ever Non-e-cigarette 7.06
4 2015 Current Non-e-cigarette 3.35
5 2016 Ever E-cigarette 4.54
6 2016 Current E-cigarette 1.23
plot1c <- nyts_data %>%
dplyr::group_by(year) %>%
dplyr::summarize("Ever_E-cigarette" =
(mean(ecig_only_ever, na.rm = TRUE) * 100),
"Current_E-cigarette" =
(mean(ecig_only_current, na.rm = TRUE) * 100),
"Ever_Non-e-cigarette" =
(mean(non_ecig_only_ever, na.rm = TRUE) * 100),
"Current_Non-e-cigarette" =
(mean(non_ecig_only_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = -year,
names_to = "User",
values_to = "Percentage of students") %>%
separate(User, into = c("User", "Product"), sep = "_") %>%
ggplot(aes(x = year, y = `Percentage of students`, color = Product)) +
geom_line(aes(linetype = User)) +
geom_point(show.legend = FALSE, size = 2) +
# this allows us to choose what type of line we want for each line
scale_linetype_manual(values = c(2, 1)) +
# this allows us to specify how the y-axis should appear
scale_y_continuous(breaks = seq(0, 30, by = 10),
labels = seq(0, 30, by = 10),
limits = c(0, 30)) +
scale_color_manual(values = v_colors) +
# this adjusts the background style of the plot
theme_linedraw() +
# this moves the legend to the bottom of the plot and removes the x axis title
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title =
"How has use of only e-cigarettes and
only tobacco products besides e-cigarettes varied over time?",
y = "% of students")
plot1c

Very interesting! We can see from this plot that the percentage of students who had currently used (or ever tried) only e-cigarettes greatly increased starting in 2017, while in contrast the percentage of students who had ever tried only non-e-cigarette tobacco products actually diminished over time. In fact, we can see that in 2019 the percentage of students who were current e-cigarette users surpassed the percentage that had tried a non-e-cigarette product even just once.
Recall that we made a variable called Group that identified students who used either just e-cigarette products, just other tobacco products (besides e-cigarettes), or students who used both e-cigarettes and some other type of tobacco product.
# A tibble: 4 x 2
Group n
<chr> <int>
1 Combination of products 16517
2 Neither 61738
3 Only e-cigarettes 7866
4 Only other products 9344
We will now make a plot over time of each of these groups. Since we will have 4 total groups, we will use 4 of the viridis colors. Notice, that in this case we are grouping by three variables by simply separating the variables that we want to group by with a comma in our group_by() function like this: group_by(Group, year, n).
# A tibble: 6 x 5
# Groups: Group, year [6]
Group year n group_count `Percentage of students`
<chr> <dbl> <int> <int> <dbl>
1 Combination of products 2015 17711 3634 20.5
2 Combination of products 2016 20675 3297 15.9
3 Combination of products 2017 17872 2623 14.7
4 Combination of products 2018 20189 3321 16.4
5 Combination of products 2019 19018 3642 19.2
6 Neither 2015 17711 11188 63.2

We can see that the majority of students did not report using any tobacco products. Of the students that did report using tobacco products, the majority of the students used both e-cigarettes and some other tobacco product. Again, a much larger percentage reported using only e-cigarettes rather than only other tobacco products in 2019.
We will further explore the relationship between e-cigarette usage and other tobacco products a bit later in the case study.
Question 2
Now we want to look how e-cigarette smoking rates compare between males and females across time.
We will calculate the percent ever and current e-cigarette users for each year and sex category again using the group_by() function and the summarize() function. We will again use the pivot_longer function to convert our data to long format.
As discussed above, we acknowledge that while gender and sex are not actually binary, the data used in this analysis only contain information for groups of individuals who answered the survey questions as male or female. For individuals that have NA values, it is unclear if the question was not answered or if the individual identifies as non-binary. Because of this uncertainty, we will filter these individuals out.
# A tibble: 6 x 4
# Groups: year [2]
year Sex User `Percentage of students`
<dbl> <fct> <chr> <dbl>
1 2015 male Ever 29.3
2 2015 male Current 13.3
3 2015 female Ever 24.3
4 2015 female Current 9.05
5 2016 male Ever 24.1
6 2016 male Current 8.72
plot2 <- nyts_data %>%
filter(!is.na(Sex)) %>%
group_by(year, Sex) %>%
summarize(Ever = (mean(EELCIGT, na.rm = TRUE) * 100),
Current = (mean(CELCIGT, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = Ever:Current,
names_to = "User",
values_to = "Percentage of students") %>%
ggplot(aes(x = year, y = `Percentage of students`, color = Sex)) +
geom_line(aes(linetype = User)) +
geom_point(show.legend = FALSE, size = 2) +
scale_linetype_manual(values = c(2, 1)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does e-cigarette usage compare between males and females?",
subtitle = "Current and ever users by sex",
y = "% of students")
plot2

It looks like the rates are fairly similar between the sexes, however the rate for males appears to be consistently higher across time.
Question 3
We are also interested in what vaping brands and flavors appear to be used the most frequently. Only the 2019 data set has this information. Therefore, we will filter for just this year using the filter() function of the dplyr package. We will use the summarize() function slightly differently this time, to calculate the total number of students using each brand using the n() function and the sum() function to calculate the percent for each brand based on the counts. We will also reorder the factor levels for the brand names so that they are in descending order of percent use, using the fct_reorder() function from dplyr. This will make them appear in decreasing order of percent use on the plot.
We will make a bar plot this time by using geom_bar. Importantly we assign the stat argument to identity, so that we are using the percentages that we calculated not the counts which is what is used by default. When color in specified outside of the aes() argument, this determines the border color of the bars, which in this case will be black.
# A tibble: 7 x 4
brand_ecig n total Percent
<fct> <int> <int> <dbl>
1 Blu 111 3604 3.08
2 JUUL 2028 3604 56.3
3 Logic 36 3604 0.999
4 MarkTen 32 3604 0.888
5 NJOY 44 3604 1.22
6 Other 1253 3604 34.8
7 Vuse 100 3604 2.77

Juul appears to be the most widely used brand. This is in agreement with a recent article, whose most recent data was from 2017:
We are also interested in how the usage of different flavors has changed over time.
To evaluate this we will calculate the percentage of students using each flavor each year - this includes usage of any type of flavored tobacco product. We will exclude 2015 data, as no specific flavor questions were asked at that time.
Recall that NA values are not included in calculating the total count for our percentages. However all of these flavor questions had complete reporting and did not have NA values. Therefore, these values reflect the percentage of students reporting using a particular favor out of all students surveyed (including those that did not use any tobacco products). Also students were allowed to select more than one flavor. You can see whether these variables had complete reporting by checking the NA values using the base summary function. Alternatively you can create a visual representation using the vis_miss() function of the naniar package.

The plot above confirms that these variables have no NA values (because all fields indicate 100% of data is present).
plot4 <- nyts_data %>%
filter(year != 2015) %>%
group_by(year) %>%
summarize(Menthol = (mean(menthol) * 100),
`Clove or Spice` = (mean(clove_spice) * 100),
Fruit = (mean(fruit) * 100),
Chocolate = (mean(chocolate) * 100),
`Alcoholic Drink` = (mean(alcoholic_drink) * 100),
`Candy/Desserts/Sweets` = (mean(candy_dessert_sweets) * 100),
Other = (mean(other) * 100)) %>%
pivot_longer(cols = -year,
names_to = "Flavor",
values_to = "Percentage of students") %>%
rename(Year = year) %>%
ggplot(aes(y = `Percentage of students`,
x = Year,
fill = reorder(Flavor, `Percentage of students`))) +
geom_bar(stat = "identity", position = "dodge", color = "black") +
scale_fill_viridis(discrete = TRUE) +
theme_linedraw() +
guides(fill = guide_legend("Flavor")) +
labs(title = "What flavors appear to be used the most frequently?",
subtitle = "Flavors of tobacco products used in the past 30 days")
plot4

From this plot, we can see that fruit flavors are the most widely used products, followed by menthol or mint flavored products. We can also see that there was a general increase in the usage of flavored products over time.
We will now look specifically at the usage of flavored e-cigarette products vs other flavored tobacco products.
Recall that we made a variable called Group that identified students who used either just e-cigarette/vaping products, just other tobacco products (besides e-cigarettes), or students who used both e-cigarettes and some other type of tobacco product. We will compare the usage of these flavors for these different groups. We also perform some data summaries to decide how to order the panels (flavors) for display.
v_colors = viridis(5)[1:4]
plot5 <- nyts_data %>%
filter(year != 2015) %>%
group_by(year, Group) %>%
summarize(Menthol = (mean(menthol) * 100),
`Clove or Spice` = (mean(clove_spice) * 100),
Fruit = (mean(fruit) * 100),
Chocolate = (mean(chocolate) * 100),
`Alcoholic Drink` = (mean(alcoholic_drink) * 100),
`Candy/Desserts/\nSweets` = (mean(candy_dessert_sweets) * 100),
Other = (mean(other) * 100),
Respondents = n()) %>%
# converting columns between and including Menthol and Other to one column called Flavor
pivot_longer(cols = Menthol:Other,
names_to = "Flavor",
values_to = "Percentage of students") %>%
group_by(Flavor) %>%
# calculate the count of students in the year/group combination who used that flavor
mutate(affirmative = (Respondents * `Percentage of students`) / 100) %>%
# calculate the fraction of total respondents who used that flavor
mutate(flavor_mean = sum(affirmative) / sum(Respondents)) %>%
ungroup() %>%
# reorder the levels of Flavor to be in increasing order of percent of students
mutate(flavor_mean_rank = dense_rank(flavor_mean),
Flavor = fct_reorder(Flavor, flavor_mean_rank)) %>%
ggplot(aes(x = year,
y = `Percentage of students`,
color = Group)) +
facet_grid(~Flavor) +
geom_line() +
geom_point(show.legend = FALSE, size = 2) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank(),
axis.text.x = element_text(angle = 90),
strip.text.x = element_text(size = 10, face = "bold")) +
labs(title = "Among different product users, what flavors are most frequently used?")
plot5

We can see from this plot that there has been an increase in the number of students reporting using flavored tobacco products. Users who use both e-cigarettes and other tobacco products appear to report using flavored products the most, followed by users who only use e-cigarettes.
Question 4
Is there a relationship between e-cigarette use and tobacco use? Now we will investigate the usage of e-cigarettes compared to other tobacco products in greater depth.
First let’s take a look at how e-cigarette usage and cigarette usage compare. We will select the data that specifically has to do with these products.
v_colors = viridis(6)[c(1, 4)]
nyts_data %>%
group_by(year) %>%
summarize("Cigarettes, Ever" = (mean(ECIGT, na.rm = TRUE) * 100),
"E-cigarettes, Ever" = (mean(EELCIGT, na.rm = TRUE) * 100),
"Cigarettes, Current" = (mean(CCIGT, na.rm = TRUE) * 100),
"E-cigarettes, Current" = (mean(CELCIGT, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = - year,
names_to = "Category",
values_to = "Percentage of students") %>%
separate(Category, into = c("Product", "User"), sep = ", ") %>%
head()
# A tibble: 6 x 4
year Product User `Percentage of students`
<dbl> <chr> <chr> <dbl>
1 2015 Cigarettes Ever 21.3
2 2015 E-cigarettes Ever 26.9
3 2015 Cigarettes Current 6.23
4 2015 E-cigarettes Current 11.2
5 2016 Cigarettes Ever 19.1
6 2016 E-cigarettes Ever 22.1
plot6 <- nyts_data %>%
group_by(year) %>%
summarize("Cigarettes, Ever" = (mean(ECIGT, na.rm = TRUE) * 100),
"E-cigarettes, Ever" = (mean(EELCIGT, na.rm = TRUE) * 100),
"Cigarettes, Current" = (mean(CCIGT, na.rm = TRUE) * 100),
"E-cigarettes, Current" = (mean(CELCIGT, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = - year,
names_to = "Category",
values_to = "Percentage of students") %>%
separate(Category, into = c("Product", "User"), sep = ", ") %>%
ggplot(aes(x = year,
y = `Percentage of students`,
color = Product,
linetype = User)) +
geom_line() +
geom_point(show.legend = FALSE, size = 2) +
scale_linetype_manual(values = c(2, 1)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does e-cigarette use compare to cigarette use?",
subtitle = "Current and ever users of e-cigarettes and cigarettes",
y = "% of students")
plot6

Interesting! we can see that in 2019 the percentage of students that reported currently using e-cigarettes had surpassed those that ever tried (even just once) a cigarette. Overall cigarette usage appears to be declining over time. This is not the case for e-cigarettes.
Now we will look at students who reported that they had ever tried e-cigarettes or non-cigarette products. In this case we will not separate out users who specifically only used one or the other. Therefore, the students included in this plot who reported as having ever tried e-cigarettes might also be current users of non-e-cigarette products or may have at least tried non-e-cigarette products.
v_colors = viridis(6)[c(1, 4)]
plot7 <- nyts_data %>%
group_by(year) %>%
summarize(`e-cigarette_ever` = (mean(ecig_ever, na.rm = TRUE) * 100),
`non-e-cigarette_ever` = (mean(non_ecig_ever, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = - year,
names_to = "Category",
values_to = "Percentage of students") %>%
separate(Category, into = c("Product", "User"), sep = "_") %>%
ggplot(aes(x = year,
y = `Percentage of students`,
color = Product)) +
geom_line() +
geom_point(show.legend = FALSE, size = 2) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0, 60)) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does the rate of ever trying e-cigarettes
compare to ever trying other products over time?",
y = "% of students")
plot7

Now we will do the same, but for students who reported currently using e-cigarettes or non-e-cigarette products.
v_colors = viridis(6)[c(1, 4)]
plot8 <- nyts_data %>%
group_by(year) %>%
summarize(`e-cigarette_current` = (mean(ecig_current, na.rm = TRUE) * 100),
`non-e-cigarette_current` = (mean(non_ecig_current, na.rm = TRUE) * 100)) %>%
pivot_longer(cols = - year,
names_to = "Category",
values_to = "Percentage of students") %>%
separate(Category, into = c("Product", "User"), sep = "_") %>%
ggplot(aes(x = year, y = `Percentage of students`, color = Product)) +
geom_line(linetype = "dashed") +
geom_point(show.legend = FALSE, size = 2) +
scale_color_manual(values = v_colors) +
scale_linetype_manual(values = c(1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0, 60)) +
theme_linedraw() +
theme(legend.position = "bottom",
axis.title.x = element_blank()) +
labs(title = "How does the rate of currently using e-cigarettes
compare to currently using other products over time?",
y = "% of students")
plot8

Putting plots together
Now we will put these plots together using the plot_grid() function of the cowplot package. We will also modify the labels using the ggdraw() function, which is also part of the cowplot package.
plotA_uw <- plot1 +
theme(axis.title.x = element_blank(),
legend.position = "none") +
labs(title = "Tobacco product users more prevalent after 2017",
subtitle = NULL,
y = "% of students")
plotB_uw <- plot7 +
theme(axis.title.x = element_blank(),
legend.position = "none") +
labs(title = "% Ever trying e-cigarettes increases &
% Ever trying other products decreases",
subtitle = NULL,
y = "% of students")
plotC_uw <- plot8 +
theme(axis.title.x = element_blank(),
legend.position = "none") +
labs(title = "% Currently using e-cigarettes increases &
% Currently using other products decreases",
subtitle = NULL,
y = "% of students")
title_uw <- ggdraw() +
draw_label(
"Is there a relationship between e-cigarette use and tobacco use?",
fontface = 'bold',
size = 14,
x = 0,
hjust = 0
) +
theme(
plot.margin = margin(0, 0, 0, 0)
)
plotsA_uw <- plot_grid(plotA_uw,
rel_widths = c(1, 1))
plotsBC_uw <- plot_grid(plotB_uw,
plotC_uw,
rel_widths = c(1, 1))
# this will take the legend from plot1c to use as the legend for the plot we are creating
legend_uw <- get_legend(plot1c +
theme(legend.position = "bottom",
legend.direction = "horizontal"))
figure_uw <- plot_grid(title_uw,
plotsA_uw,
plotsBC_uw,
legend_uw,
ncol = 1,
rel_heights = c(0.1,
1,
1,
0.1),
scale = 1.0)
figure_uw

Survey Weighting **
It turns out that our analysis thus far has been brushing an important statistical concept under the rug, related to how our data were collected. Our data come from responses to a survey, which may have a particular sampling scheme to capture data about the population we are interested in. For example, the survey may be designed to capture a set of individuals who reflect the characteristics of the population that we are interested in drawing conclusions about. However, only a fraction of the individuals who were contacted about taking the survey may have completed it, and this fraction of individuals may no longer be representative of the population. Or the survey may be designed to over-sample a particular group of interest so that individuals from that group show up more often as survey respondents than are present in the population overall. In order to account for the fact that the survey respondents may not reflect the composition of the population we want to generalize to, we can employ a technique called survey weighting.
Survey weighting is a common technique used in survey data analysis because often the individuals that take a survey are not necessarily representative of the population that we are trying to gather information about. For example, we may have more females that respond to the survey than males because perhaps female students were more willing to participate. In this case, the proportion of data values in our data will be smaller for the males than the proportion of actual male students and larger for the females than the true proportion of actual female students. To get a better estimate of overall e-cigarette smoking rates, the data from the males can be weighted based on the true proportion of male students to amplify the contribution of the responses from the males that did participate. Conversely, the female data can be weighted to diminish the contribution if their responses to the overall picture. We will see if using survey weighting changes the general trends that we see in our data.
Calculating survey weights involves making a weight based on the ratio of the proportion of survey respondents from a particular group and the actual proportion of that group in the population. For example, let’s say that females account for 50% of the population and males account for 50 % of the population. Let’s also say that 75% of the respondents to the survey were female and only 25% were males.
Then we could calculate survey weights using this formula:
\[ \frac{\text{actual proportion of group in the population}}{\text{ proportion of group in the respondents}}\]
Thus the weight for the females would be calculated as:
\[ \frac{.5}{.75} = .67\]
The weight for the males would be calculated as:
\[ \frac{.5}{.25} = 2\]
Therefore each male response value would be multiplied by a factor of 2 and would have twice the contribution, while the female response values would have only about 70% of the contribution that they would have had without weighting.
Note that survey weights are in reality corrected for other aspects - for example the response rate to individual questions.
We do not need to calculate survey weights for our data as they were already supplied in the data set, as described in the codebooks.
srvyr package and survey design
We will now use the srvyr package to evaluate our data using survey weights that were provided in the data for each year, as described in the respective codebooks. This package contains functions that allow the user to easily perform calculations from the data that take the survey design into account, without having to work out the math by hand.
Within the data you will see that we have three variables related to the survey sampling scheme: psu, finwgt, and stratum. Details about these variables are available, for example, in the 2019 Methodology Report.
In brief they represent:
psu: Surveys like the one used to create the data we are using often sample people based on strata. This is done to ensure that the responses are representative of the population of interest. Thus, often people first think about ensuring that surveys are conducted in a variety of geographical areas. This is often called the primary sampling unit or PSU. In this survey, the county where the student’s school was located was used as the PSU.
stratum: A categorical variable that indicates subsets of the data that include respondents from different PSUs. In our case, strata are determined by the predominant minority in the PSU (Non-Hispanic Black or Hispanic), whether the PSU is urban or non-urban, and what percent of the students in the PSU fall into the predominant minority group. PSUs are allocated across the 16 possible strata according to the sampling scheme. These strata values allow estimates based on the survey responses to be calculated using different strata allowing for improved precision of the response estimates.
finwgt: The survey weight which was calculated based on a variety of factors.
This link and this link have more information about the study design of the data that we are using.
For detailed information on such survey designs in general see here and here.
We will use the as_survey_design() function of the srvyrpackage to create a survey object with a specified survey design. This is a special R object that includes information about how the survey was conducted that can be taken into account in the analysis.
There are several arguments to pay attention to:
- The
strata argument is used to specify the variable(s) that defined strata in the data. In this case, we will use the stratum variable.
- The
ids argument is used to define cluster ids within the data. In this case we will use the psu variable.
- The
weight argument is the used to define which variable(s) are the survey weights.
- The
nest = TRUE argument, forces cluster ids (in this case the PSU) to be nested within the strata.
We can then use the survey_mean() function to calculate percentages of students who report using tobacco for each year while accounting for the survey design and weights. We will specify that we want confidence interval estimates by using the vartype = "ci" argument. The confidence intervals in our case give a range of possible values for the true population mean based on the data observed in the survey. We will multiply these values by 100 to get percentages. (Note: We could also have calculated confidence intervals for the unweighted results above by computing them by hand; we leave this as a potential exercise.)
Since the survey weights are specific to a single year of the survey results, we need to create survey design objects for each year separately. We will use group_by and group_modify, which is also from the dplyr package, to do this. We first write the function that we want to call on each group.
This function takes an input called currYear, which will be one set of survey responses for a specific year, and then creates a survey design based on the stratum and finwgt values specific to that year. It then calculates the percent of student respondents who have ever tried any tobacco products or who are a current user of any tobacco products accounting for the survey design and weights using survey_mean() as was just described. The function then wrangles the data to convert the means to percentages and reformat the data in long form for plotting.
One technical note: since some years have strata with a single PSU, we need to tell the survey weighting package how to handle estimating within strata variances. The line options(survey.lonely.psu = "adjust") tells R to center the stratum with the single PSU on the sample grand mean, a conservative approach to solving the problem. See further information here and here.
Weighted Sample
First, we show the basic output of the survey_mean function by year. Since we include the argument vartype = "ci", we get a mean and upper and lower confidence interval bounds for the mean.
# A tibble: 5 x 7
# Groups: year [5]
year tobacco_ever tobacco_ever_low tobacco_ever_upp tobacco_current
<dbl> <dbl> <dbl> <dbl> <dbl>
1 2015 0.372 0.344 0.400 0.180
2 2016 0.338 0.319 0.358 0.148
3 2017 0.307 0.284 0.330 0.139
4 2018 0.339 0.318 0.360 0.185
5 2019 0.408 0.384 0.432 0.233
# … with 2 more variables: tobacco_current_low <dbl>, tobacco_current_upp <dbl>
Now let’s make the function wrangle the output in a more usable form too:
surveyMeanA <- function(currYear) {
options(survey.lonely.psu = "adjust")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(tobacco_ever = survey_mean(tobacco_ever,
vartype = "ci",
na.rm = TRUE),
tobacco_current = survey_mean(tobacco_current,
vartype = "ci",
na.rm = TRUE)) %>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Type",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(str_detect(Type, "_low") ~ "Lower",
str_detect(Type, "_upp") ~ "Upper",
TRUE ~ "Mean"),
User = case_when(str_detect(Type, "ever") ~ "Ever",
str_detect(Type, "current") ~ "Current",
TRUE ~ "Mean"))}
nyts_data %>%
group_by(year) %>%
group_modify(~ surveyMeanA(.x))
# A tibble: 30 x 5
# Groups: year [5]
year Type `Percentage of students` Estimate User
<dbl> <chr> <dbl> <chr> <chr>
1 2015 tobacco_ever 37.2 Mean Ever
2 2015 tobacco_ever_low 34.4 Lower Ever
3 2015 tobacco_ever_upp 40.0 Upper Ever
4 2015 tobacco_current 18.0 Mean Current
5 2015 tobacco_current_low 16.2 Lower Current
6 2015 tobacco_current_upp 19.9 Upper Current
7 2016 tobacco_ever 33.8 Mean Ever
8 2016 tobacco_ever_low 31.9 Lower Ever
9 2016 tobacco_ever_upp 35.8 Upper Ever
10 2016 tobacco_current 14.8 Mean Current
# … with 20 more rows
We will now make a plot using this data. The confidence intervals are included using the geom_linerange() function of the ggplot2 package.
plotA_w <- nyts_data %>%
group_by(year) %>%
group_modify(~ surveyMeanA(.x)) %>%
dplyr::select(-Type) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`) %>%
ggplot(aes(x = year, y = Mean)) +
geom_line(aes(linetype = User)) +
geom_linerange(aes(ymin = Lower,
ymax = Upper),
size = 1,
show.legend = FALSE) +
scale_linetype_manual(values = c(2, 1)) +
scale_y_continuous(breaks = seq(0, 70, by = 10),
labels = seq(0, 70, by = 10),
limits = c(0, 70)) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "Tobacco product users more prevalent after 2017",
y = "% of students")
plotA_w

Now we can see that we have confidence interval ranges plotted for each value.
We will make a similar plot for students who reported ever trying or who currently use e-cigarettes as opposed to tobacco in general.
v_colors = viridis(6)[c(1, 4)]
surveyMeanB <- function(currYear) {
options(survey.lonely.psu = "adjust")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(ecig_ever_year = survey_mean(ecig_ever,
vartype = "ci",
na.rm = TRUE),
non_ecig_ever_year = survey_mean(non_ecig_ever,
vartype = "ci",
na.rm = TRUE)) %>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(str_detect(Category, "_low") ~ "Lower",
str_detect(Category, "_upp") ~ "Upper",
TRUE ~ "Mean"),
User = case_when(str_detect(Category, "ever") ~ "Ever",
str_detect(Category, "current") ~ "Current"),
Product = case_when(str_detect(Category, "non_ecig") ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)}
nyts_data %>%
group_by(year) %>%
group_modify(~ surveyMeanB(.x)) %>%
head()
# A tibble: 6 x 6
# Groups: year [3]
year User Product Mean Lower Upper
<dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 2015 Ever E-cigarettes 26.6 24.3 29.0
2 2015 Ever Other products 31.3 28.7 33.8
3 2016 Ever E-cigarettes 22.6 21.0 24.3
4 2016 Ever Other products 28.2 26.2 30.2
5 2017 Ever E-cigarettes 21.1 19.1 23.2
6 2017 Ever Other products 24.3 22.2 26.4
plotB_w <- nyts_data %>%
group_by(year) %>%
group_modify(~ surveyMeanB(.x)) %>%
ggplot(aes(x = year, y = Mean, color = Product)) +
geom_line() +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1, show.legend = FALSE) +
scale_linetype_manual(values = c(2, 1)) +
scale_color_manual(values = v_colors) +
scale_y_continuous(breaks = seq(0, 60, by = 10),
labels = seq(0, 60, by = 10),
limits = c(0, 60)) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% Ever trying e-cigarettes increases &
% Ever trying other products decreases",
y = "% of students")
plotB_w

Now we will do the same but for current users:
surveyMeanC <- function(currYear) {
options(survey.lonely.psu = "adjust")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(ecig_current_year = survey_mean(ecig_current,
vartype = "ci",
na.rm = TRUE),
non_ecig_current_year = survey_mean(non_ecig_current,
vartype = "ci",
na.rm = TRUE)) %>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(str_detect(Category, "_low") ~ "Lower",
str_detect(Category, "_upp") ~ "Upper",
TRUE ~ "Mean"),
User = case_when(str_detect(Category, "ever") ~ "Ever",
str_detect(Category, "current") ~ "Current"),
Product = case_when(str_detect(Category, "non_ecig") ~ "Other products",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)}
plotC_w <- nyts_data %>%
group_by(year) %>%
group_modify(~ surveyMeanC(.x)) %>%
ggplot(aes(x = year, y = Mean, color = Product)) +
geom_line(aes(linetype = "dashed")) +
geom_linerange(aes(ymin = Lower, ymax = Upper),
size = 1,
show.legend = FALSE) +
scale_linetype_manual(values = c(2, 1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0, 60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% Currently using e-cigarettes increases &
% Currently using other products decreases",
y = "% of students")
plotC_w

Now we will put these plots together again using the cowplot package:
title_w <- ggdraw() +
draw_label(
expression("What is the relationship between e-cigarette use and tobacco use?"),
fontface = 'bold',
size = 14,
x = 0,
hjust = 0
) +
theme(
plot.margin = margin(0, 0, 0, 0)
)
plotsA_w <- plot_grid(plotA_w,
rel_widths = c(1),
align = "v",
axis = "bt")
plotsBC_w <- plot_grid(plotB_w,
plotC_w,
rel_widths = c(1, 1),
align = "v",
axis = "bt")
legend_w <- get_legend(plot1c +
theme(legend.position = "bottom",
legend.direction = "horizontal"))
figure_w <- plot_grid(title_w,
plotsA_w,
plotsBC_w,
legend_w,
ncol = 1,
rel_heights = c(0.1,
1,
1,
0.1),
scale = 1.0)
figure_w

We can see that these figures look quite similar to the ones generated without using the survey weights.
Artificial Cohort
Although the survey design does not allow specific individuals to be followed over time, we will use certain subsets of the data from each year to construct an artificial cohort where we follow students of the same age group as they get older. This will allow us to look at how tobacco usage changed for students who were in 8th grade in 2015 as they aged.
All of the data so far has included all 6th-12th graders every year. Now we will look at just the data for students expected to graduate in 2019. These are the students who were in 8th grade in 2015, most of whom were 9th graders in 2016, 10th graders in 2017 and so on. We will filter the data to just the students expected to be in the graduating class of 2019.
surveyMeanCohort <- function(currYear) {
options(survey.lonely.psu = "adjust")
currYear %>%
as_survey_design(strata = stratum,
ids = psu,
weight = finwgt,
nest = TRUE) %>%
summarize(ecig_ever_year =
survey_mean(ecig_ever, vartype = "ci", na.rm = TRUE),
ecig_current_year =
survey_mean(ecig_current, vartype = "ci", na.rm = TRUE),
non_ecig_ever_year =
survey_mean(non_ecig_ever, vartype = "ci", na.rm = TRUE),
non_ecig_current_year =
survey_mean(non_ecig_current, vartype = "ci", na.rm = TRUE),
tobacco_ever_year =
survey_mean(tobacco_ever, vartype = "ci", na.rm = TRUE),
tobacco_current_year =
survey_mean(tobacco_current, vartype = "ci", na.rm = TRUE)) %>%
mutate_all("*", 100) %>%
pivot_longer(everything(),
names_to = "Category",
values_to = "Percentage of students") %>%
mutate(Estimate = case_when(str_detect(Category, "_low") ~ "Lower",
str_detect(Category, "_upp") ~ "Upper",
TRUE ~ "Mean"),
User = case_when(str_detect(Category, "ever") ~ "Ever",
str_detect(Category, "current") ~ "Current"),
Product = case_when(str_detect(Category, "non_ecig") ~ "Other products",
str_detect(Category, "tobacco") ~ "Any tobacco product",
TRUE ~ "E-cigarettes")) %>%
dplyr::select(-Category) %>%
pivot_wider(names_from = Estimate,
values_from = `Percentage of students`)}
Cohort_data <- nyts_data %>%
filter((Grade == "8" & year == 2015) |
(Grade == "9" & year == 2016) |
(Grade == "10" & year == 2017) |
(Grade == "11" & year == 2018) |
(Grade == "12" & year == 2019)
) %>%
group_by(year) %>%
group_modify(~ surveyMeanCohort(.x))
head(Cohort_data)
# A tibble: 6 x 6
# Groups: year [1]
year User Product Mean Lower Upper
<dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 2015 Ever E-cigarettes 20.1 17.0 23.1
2 2015 Current E-cigarettes 8.12 6.74 9.50
3 2015 Ever Other products 20.7 17.7 23.7
4 2015 Current Other products 7.06 5.63 8.49
5 2015 Ever Any tobacco product 26.9 23.3 30.4
6 2015 Current Any tobacco product 10.9 9.13 12.6
We will now make similar plots to those above for this subset of the data:
plotA_w_8 <- Cohort_data %>%
filter(Product == "Any tobacco product") %>%
ggplot(aes(x = year, y = Mean)) +
geom_line(aes(linetype = User)) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1) +
scale_linetype_manual(values = c(2, 1)) +
scale_y_continuous(breaks = seq(0, 70, by = 10),
labels = seq(0, 70, by = 10),
limits = c(0, 70)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "Tobacco product use became increasingly prevalent",
y = "% of students")
plotB_w_8 <- Cohort_data %>%
filter(Product != "Any tobacco product", User == "Ever") %>%
ggplot(aes(x = year, y = Mean, color = Product)) +
geom_line(linetype = 1) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1) +
scale_y_continuous(breaks = seq(10, 60, by = 10), limits = c(10, 60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "% ever trying tobacco products increases",
y = "% of students")
plotC_w_8 <- Cohort_data %>%
filter(Product != "Any tobacco product", User == "Current") %>%
ggplot(aes(x = year, y = Mean, color = Product)) +
geom_line(aes(linetype = User)) +
geom_linerange(aes(ymin = Lower, ymax = Upper), size = 1) +
scale_linetype_manual(values = c(2, 1)) +
scale_y_continuous(breaks = seq(0, 60, by = 10), limits = c(0, 60)) +
scale_color_manual(values = v_colors) +
theme_linedraw() +
theme(legend.position = "none",
axis.title.x = element_blank()) +
labs(title = "E-cigarette use surpasses use of other products",
y = "% of students")
title_w_8 <- ggdraw() +
draw_label(
expression("For students in the 2019 graduating class, how are vaping and tobacco use related?"),
fontface = 'bold',
size = 14,
x = 0,
hjust = 0
) +
theme(
plot.margin = margin(0, 0, 0, 0)
)
plotsA_w_8 <- plot_grid(plotA_w_8,
rel_widths = c(1),
align = "v",
axis = "bt")
plotsBC_w_8 <- plot_grid(plotB_w_8,
plotC_w_8,
rel_widths = c(1, 1),
axis = "bt")
legend_w_8 <- get_legend(plot1c +
theme(legend.position = "bottom",
legend.direction = "horizontal"))
figure_w_8 <- plot_grid(title_w_8,
plotsA_w_8,
plotsBC_w_8,
legend_w_8,
ncol = 1,
rel_heights = c(0.1,
1,
1,
0.1),
scale = 1.0
)
figure_w_8

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBWYXBpbmcgQmVoYXZpb3JzIGluIEFtZXJpY2FuIFlvdXRoIgoKY3NzOiBzdHlsZS5jc3MKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKCi0tLQo8c3R5bGU+CiNUT0MgewogYmFja2dyb3VuZDogdXJsKCJodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vaW1nL2ljb24tYmFoaS5wbmciKTsKICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47CiAgcGFkZGluZy10b3A6IDI0MHB4ICFpbXBvcnRhbnQ7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKfQo8L3N0eWxlPgoKYGBge3IsIGVjaG89RkFMU0V9CmtuaXRfdGltZV9zdGFydCA8LSBTeXMudGltZSgpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDgsIGRwaSA9IDMwMCkKYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKYGBgCgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImZpbmFsX3Bsb3QucG5nIikpCmBgYAojIyMjCgoKCgojIyB7LmRpc2NsYWltZXJfYmxvY2t9CgoqKkRpc2NsYWltZXIqKjogVGhlIHB1cnBvc2Ugb2YgdGhlIFtPcGVuIENhc2UgU3R1ZGllc10oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvKXt0YXJnZXQ9Il9ibGFuayJ9IHByb2plY3QgaXMgKip0byBkZW1vbnN0cmF0ZSB0aGUgdXNlIG9mIHZhcmlvdXMgZGF0YSBzY2llbmNlIG1ldGhvZHMsIHRvb2xzLCBhbmQgc29mdHdhcmUgaW4gdGhlIGNvbnRleHQgb2YgbWVzc3ksIHJlYWwtd29ybGQgZGF0YSoqLiBBIGdpdmVuIGNhc2Ugc3R1ZHkgZG9lcyBub3QgY292ZXIgYWxsIGFzcGVjdHMgb2YgdGhlIHJlc2VhcmNoIHByb2Nlc3MsIGlzIG5vdCBjbGFpbWluZyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gYW5hbHl6ZSBhIGdpdmVuIGRhdGEgc2V0LCBhbmQgc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoZSBjb250ZXh0IG9mIG1ha2luZyBwb2xpY3kgZGVjaXNpb25zIHdpdGhvdXQgZXh0ZXJuYWwgY29uc3VsdGF0aW9uIGZyb20gc2NpZW50aWZpYyBleHBlcnRzLiAKCiMjIHsubGljZW5zZV9ibG9ja30KClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsIDMuMCBbKENDIEJZLU5DIDMuMCldKGh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy8zLjAvdXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICBVbml0ZWQgU3RhdGVzIExpY2Vuc2UuCgoKIyMgey5yZWZlcmVuY2VfYmxvY2t9CgpUbyBjaXRlIHRoaXMgY2FzZSBzdHVkeSBwbGVhc2UgdXNlOgoKV3JpZ2h0LCBDYXJyaWUgYW5kIE9udGl2ZXJvcywgTWljaGFlbCBhbmQgSmFnZXIsIExlYWggYW5kIFRhdWIsIE1hcmdhcmV0IGFuZCBIaWNrcywgU3RlcGhhbmllLiAoMjAyMCkuIGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJsb29tYmVyZy12YXBpbmctY2FzZS1zdHVkeS4gVmFwaW5nIEJlaGF2aW9ycyBpbiBBbWVyaWNhbiBZb3V0aCAoVmVyc2lvbiB2MS4wLjApLgoKIyMgKipNb3RpdmF0aW9uKioKKioqIApBY2NvcmRpbmcgdG8gYSByZWNlbnQgW3JlcG9ydF0oaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjgvd3IvbW02ODA2ZTEuaHRtP3NfY2lkPW1tNjgwNmUxX3cpe3RhcmdldD0iX2JsYW5rIn0sIG92ZXJhbGwgdG9iYWNjbyB1c2UgKippbmNyZWFzZWQqKiBpbiB5b3V0aHMgKG1pZGRsZSBzY2hvb2wgYW5kIGhpZ2ggc2Nob29sIHN0dWRlbnRzKSBpbiB0aGUgVW5pdGVkIFN0YXRlcyBpbiAyMDE3IGFuZCAyMDE4LCBkZXNwaXRlIHByZXZpb3VzIHllYXJzIG9mIGRlY2xpbmluZyB1c2UuCgpUaGlzIG1ham9yIGluY3JlYXNlIGlzIGF0dHJpYnV0ZWQgdG8gYW4gaW5jcmVhc2UgaW4gdGhlIHVzZSBvZiBlbGVjdHJvbmljIGNpZ2FyZXR0ZSAoZS1jaWdhcmV0dGUpIHByb2R1Y3RzLgoKRS1jaWdhcmV0dGVzIGFyZSByZWZlcnJlZCB0byBieSBtYW55IGRpZmZlcmVudCBuYW1lcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bzoKCjEpIEVsZWN0cm9uaWMgbmljb3RpbmUgZGVsaXZlcnkgc3lzdGVtcyAoRU5EUykKMikgVmFwZXMKMykgZS1ob29rYWhzCjQpIHZhcGUgcGVucwo1KSB0YW5rcwo2KSBtb2RzCgpUaGUgZGV2aWNlcyB2YXJ5IGdyZWF0bHk6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQoKaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly93d3cubHVuZy5vcmcvZ2V0bWVkaWEvOGFjOGFiOGMtZTdmYy00OTdiLTgzODQtNDQxNjE1ZjUwZmYwL2VjaWdzX0suanBnLmpwZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3Lmx1bmcub3JnL3F1aXQtc21va2luZy9lLWNpZ2FyZXR0ZXMtdmFwaW5nL2x1bmctaGVhbHRoKV0KClNlZSB0aGlzIFtDREMgZ3VpZGVdKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9iYXNpY19pbmZvcm1hdGlvbi9lLWNpZ2FyZXR0ZXMvcGRmcy9lY2lnYXJldHRlLW9yLXZhcGluZy1wcm9kdWN0cy12aXN1YWwtZGljdGlvbmFyeS01MDgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCB0aGUgW0FtZXJpY2FuIEx1bmcgQXNzb2NpYXRpb24gd2Vic2l0ZV0oaHR0cHM6Ly93d3cubHVuZy5vcmcvcXVpdC1zbW9raW5nL2UtY2lnYXJldHRlcy12YXBpbmcvbHVuZy1oZWFsdGgpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgaW5mb3JtYXRpb24uIAoKVGhlIHJlcG9ydCBmb3VuZCB0aGF0OgoKPiBEdXJpbmcgMjAxN+KAkzIwMTgsIGN1cnJlbnQgdXNlIG9mIGFueSB0b2JhY2NvIHByb2R1Y3QgKippbmNyZWFzZWQgMzguMyUqKiAoZnJvbSAxOS42JSB0byAyNy4xJSkgYW1vbmcgaGlnaCBzY2hvb2wgc3R1ZGVudHMgYW5kICoqMjguNiUqKiAoZnJvbSA1LjYlIHRvIDcuMiUpIGFtb25nIG1pZGRsZSBzY2hvb2wgc3R1ZGVudHM7IGUtY2lnYXJldHRlIHVzZSAqKmluY3JlYXNlZCA3Ny44JSoqIChmcm9tIDExLjclIHRvIDIwLjglKSBhbW9uZyBoaWdoIHNjaG9vbCBzdHVkZW50cyBhbmQgKio0OC41JSoqIChmcm9tIDMuMyUgdG8gNC45JSkgYW1vbmcgbWlkZGxlIHNjaG9vbCBzdHVkZW50cy4KCgpJbiAyMDE4LCB0aGUgW0ZlZGVyYWwgRHJ1ZyBBZG1pbmlzdHJhdGlvbiAoRkRBKSBpbiB0aGUgVW5pdGVkIFN0YXRlc10oaHR0cHM6Ly9hY3Nqb3VybmFscy5vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvZnVsbC8xMC4xMDAyL2NuY3IuMzE4Njgpe3RhcmdldD0iX2JsYW5rIn0gc3RhdGVkIHRoYXQgZS1jaWdhcmV0dGUgdXNhZ2UgdXNlIGFtb25nIHlvdXRoIHJlYWNoZWQ6ICAKCj4g4oCcbm90aGluZyBzaG9ydCBvZiBhbiAqKmVwaWRlbWljIHByb3BvcnRpb24gb2YgZ3Jvd3RoKirigJ0KCgpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgYmUgaW52ZXN0aWdhdGluZyB0aGUgc2FtZSBkYXRhIHVzZWQgaW4gdGhlIHJlcG9ydCB0aGF0IGdlbmVyYXRlZCB0aGUgYWJvdmUgZmluZGluZ3MuIFRoaXMgZGF0YSBjb21lcyBmcm9tIHRoZSBbVGhlIE5hdGlvbmFsIFlvdXRoIFRvYmFjY28gU3VydmV5IChOWVRTKV0oaHR0cHM6Ly93d3cuY2RjLmdvdi90b2JhY2NvL2RhdGFfc3RhdGlzdGljcy9zdXJ2ZXlzL255dHMvaW5kZXguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9LgoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KCkdlbnR6a2UsIEFuZHJlYSBTLiwgTWVsaXNhIENyZWFtZXIsIEthcmVuIEEuIEN1bGxlbiwgQnJpZGdldCBLLiBBbWJyb3NlLCBHb3Jkb24gV2lsbGlzLCBBaG1lZCBKYW1hbCwgYW5kIEJyaWFuIEEuIEtpbmcuICDigJxWaXRhbCBTaWduczogVG9iYWNjbyBQcm9kdWN0IFVzZSBBbW9uZyBNaWRkbGUgYW5kIEhpZ2ggU2Nob29sIFN0dWRlbnRzIC0gVW5pdGVkIFN0YXRlcywgMjAxMS0yMDE4LuKAnSAqKk1NV1IuIE1vcmJpZGl0eSBhbmQgTW9ydGFsaXR5IFdlZWtseSBSZXBvcnQqKiA2OCAoNik6IDE1N+KAkzY0ICgyMDE5KS4KCiMjIyMKCgojIyAqKk1haW4gUXVlc3Rpb25zKioKKioqIAoKIyMjIyB7Lm1haW5fcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBPdXIgbWFpbiBxdWVzdGlvbjogPC91PjwvYj4KCjEpIEhvdyBoYXMgdG9iYWNjbyBhbmQgZS1jaWdhcmV0dGUvdmFwaW5nIHVzZSBieSBBbWVyaWNhbiB5b3V0aHMgY2hhbmdlZCBzaW5jZSAyMDE1PwoyKSBIb3cgZG9lcyBlLWNpZ2FyZXR0ZSB1c2UgY29tcGFyZSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzPwozKSBXaGF0IHZhcGluZyBicmFuZHMgYW5kIGZsYXZvcnMgYXBwZWFyIHRvIGJlIHVzZWQgdGhlIG1vc3QgZnJlcXVlbnRseT8gIApXZSB3aWxsIGJhc2UgdGhpcyBvbiB0aGUgZm9sbG93aW5nIHN1cnZleSBxdWVzdGlvbnM6ICAgCj4gIkR1cmluZyB0aGUgcGFzdCAzMCBkYXlzLCB3aGF0IGJyYW5kIG9mIGUtY2lnYXJldHRlcyBkaWQgeW91IHVzdWFsbHkgdXNlPyIgICAKPiAiV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdAozMCBkYXlzPyIgCgo0KSBJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGUtY2lnYXJldHRlL3ZhcGluZyB1c2UgYW5kIG90aGVyIHRvYmFjY28gdXNlPwoKIyMjIwoKIyMgKipMZWFybmluZyBPYmplY3RpdmVzKiogCioqKiAKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBjb3ZlciBob3cgdG8gaW1wb3J0IGRhdGEgZnJvbSBtdWx0aXBsZSBmaWxlcyBlZmZpY2llbnRseSwgaG93IHRvIGltcG9ydCBkYXRhIGZyb20gZXhjZWwgZmlsZXMsIGFuZCBob3cgdG8gbWFrZSBhIHZhcmlldHkgb2YgdmlzdWFsaXphdGlvbnMgdG8gY29tcGFyZSBtdWx0aXBsZSBncm91cHMgYWNyb3NzIHRpbWUuIFdlIHdpbGwgYWxzbyBkZW1vbnN0cmF0ZSBob3cgdG8gd29yayB3aXRoIGNvZGVib29rcy4gV2Ugd2lsbCBjb3ZlciB0aGUgY29uY2VwdCBvZiBzdXJ2ZXkgd2VpZ2h0aW5nIGFuZCBpbnRyb2R1Y2UgdGhlIGBzcnZ5cmAgcGFja2FnZS4gV2Ugd2lsbCBkaXNjdXNzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gcG9vbGVkIGNyb3NzLXNlY3Rpb25hbCBkYXRhIGFuZCBwYW5lbCBkYXRhLiBXZSB3aWxsIGVzcGVjaWFsbHkgZm9jdXMgb24gdXNpbmcgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmcm9tIHRoZSBbYFRpZHl2ZXJzZWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciB3cmFuZ2xpbmcgZGF0YSwgc3VjaCBhcyBgdGlkeXJgIGFuZCBgZHBseXJgIGFuZCBmb3IgdmlzdWFsaXphdGlvbiwgc3VjaCBhcyBhcyBgZ2dwbG90MmAuIFRoZSBUaWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgUlN0dWRpby4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIGVzcGVjaWFsbHkgZWZmaWNpZW50LgoKYGBge3IsIG91dC53aWR0aCA9ICIyMCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciJ9CgppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3RpZHl2ZXJzZS50aWR5dmVyc2Uub3JnL2xvZ28ucG5nIikKYGBgCgoKVGhlIHNraWxscywgbWV0aG9kcywgYW5kIGNvbmNlcHRzIHRoYXQgc3R1ZGVudHMgd2lsbCBiZSBmYW1pbGlhciB3aXRoIGJ5IHRoZSBlbmQgb2YgdGhpcyBjYXNlIHN0dWR5IGFyZToKCjx1PioqRGF0YSBTY2llbmNlIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+CgoxLiBJbXBvcnQgZGF0YSBmcm9tIEV4Y2VsIGZpbGVzCjIuIE1lcmdlIGRhdGEgZnJvbSBtdWx0aXBsZSBzaW1pbGFyIGJ1dCBub3QgaWRlbnRpY2FsIGRhdGEgc3RydWN0dXJlcwozLiBDcmVhdGUgZWZmZWN0aXZlIGxvbmdpdHVkaW5hbCBkYXRhIHZpc3VhbGl6YXRpb25zCjQuIFdyaXRlIGZ1bmN0aW9ucyBpbiBSCjUuIEFwcGx5IGZ1bmN0aW9ucyBhY3Jvc3MgZGF0YSBzdWJzZXRzIHVzaW5nIGBwdXJycmAgYW5kIGBkcGx5cmAgZnVuY3Rpb25hbGl0eS4KCjx1PioqU3RhdGlzdGljYWwgTGVhcm5pbmcgT2JqZWN0aXZlczoqKjwvdT4gCgoxLiBVbmRlcnN0YW5kaW5nIG9mIGRpZmZlcmVudCB0eXBlcyBvZiBsb25naXR1ZGluYWwgZGF0YSAKMi4gVXNhZ2Ugb2YgY29kZSBib29rcwozLiBDb25jZXB0dWFsIHVuZGVyc3RhbmRpbmcgb2Ygc3VydmV5IHdlaWdodGluZwo0LiBJbXBsZW1lbnRpbmcgbG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIHN1cnZleSB3ZWlnaHRpbmcKCgoqKiogCgoKV2Ugd2lsbCBiZWdpbiBieSBsb2FkaW5nIHRoZSBwYWNrYWdlcyB0aGF0IHdlIHdpbGwgbmVlZDoKCmBgYHtyfQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KG5hbmlhcikKbGlicmFyeShzcnZ5cikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KHN1cnZleSkKYGBgCgo8dT4qKlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OioqPC91PgoKIFBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YSAgCltyZWFkeGxdKGh0dHBzOi8vcmVhZHhsLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIGRhdGEgaW4gdGhlIGV4Y2VsIGZpbGVzIApbbWFncml0dHJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHVzZSB0aGUgY29tcG91bmQgYXNzaWdubWVudCBwaXBlIG9wZXJhdG9yIGAlPD4lYApbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvc3RyaW5nci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFuaXB1bGF0ZSB0aGUgY2hhcmFjdGVyIHN0cmluZ3Mgd2l0aGluIHRoZSBkYXRhICAKW3B1cnJyXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBpbXBvcnQgdGhlIGRhdGEgaW4gYWxsIHRoZSBkaWZmZXJlbnQgZXhjZWwgYW5kIGNzdiBmaWxlcyBlZmZpY2llbnRseQpbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgIApbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGltcG9ydCB0aGUgQ1NWIGZpbGUgZGF0YQpbdGlkeXJdKGh0dHBzOi8vdGlkeXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHJlYXJyYW5nZSBkYXRhIGluIHdpZGUgYW5kIGxvbmcgZm9ybWF0cyAKW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIG1ha2UgdmlzdWFsaXphdGlvbnMgd2l0aCBtdWx0aXBsZSBsYXllcnMKW3NjYWxlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NjYWxlcy9zY2FsZXMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gYWxsb3cgdXMgdG8gbG9vayBhdCB0aGUgY29sb3JzIHdpdGhpbiB0aGUgdmlyaWRpcyBwYWNrYWdlClt2aXJpZGlzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdmlyaWRpcy92aWduZXR0ZXMvaW50cm8tdG8tdmlyaWRpcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFrZSBwbG90cyB3aXRoIGEgY29sb3IgcGFsZXR0ZSB0aGF0IGlzIGNvbXBhdGlibGUgd2l0aCBjb2xvciBibGluZG5lc3MKW2ZvcmNhdHNdKGh0dHBzOi8vZm9yY2F0cy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIGFsbG93IGZvciByZW9yZGVyaW5nIG9mIGZhY3RvcnMgaW4gcGxvdHMKW25hbmlhcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL25hbmlhci92aWduZXR0ZXMvZ2V0dGluZy1zdGFydGVkLXctbmFuaWFyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gbWFrZSBhIHZpc3VhbGl6YXRpb24gb2YgbWlzc2luZyBkYXRhCltzeXJ2cl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NydnlyL3NydnlyLnBkZil7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHVzZSBzdXJ2ZXkgd2VpZ2h0cwpbY293cGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nvd3Bsb3QvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYWxsb3cgcGxvdHMgdG8gYmUgY29tYmluZWQgClticm9vbV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Jyb29tL3ZpZ25ldHRlcy9icm9vbS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gY3JlYXRlIG5pY2VseSBmb3JtYXR0ZWQgbW9kZWwgb3V0cHV0CltzdXJ2ZXldKGh0dHA6Ly9yLXN1cnZleS5yLWZvcmdlLnItcHJvamVjdC5vcmcvc3VydmV5L2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBmaXQgc3VydmV5LXdlaWdodGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24KCgpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4KCgojIyAqKkNvbnRleHQqKgoqKiogCgpBY2NvcmRpbmcgdG8gdGhlIGNpdGVkIFtNb3JiaWRpdHkgYW5kIE1vcnRhbGl0eSBXZWVrbHkgUmVwb3J0XShodHRwczovL3d3dy5jZGMuZ292L21td3Ivdm9sdW1lcy82OC93ci9tbTY4MDZlMS5odG0/c19jaWQ9bW02ODA2ZTFfdykgdGhpcyB3YXMgd2hhdCB3YXMgYWxyZWFkeSBrbm93biBhYm91dCB0aGlzIHRvcGljIGFuZCB0aGUgaW1wbGljYXRpb25zIG9mIHRoaXMgc3R1ZHk6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiODAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJjb250ZXh0LnBuZyIpKQpgYGAKIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjgvd3IvbW02ODA2ZTEuaHRtP3NfY2lkPW1tNjgwNmUxX3cpXXt0YXJnZXQ9Il9ibGFuayJ9IAoKSW1wb3J0YW50bHksIHRoZSB2YXBvcnMgdXNlZCBpbiBlLWNpZ2FyZXR0ZXMgY29udGFpbiBoYXJtZnVsIGNoZW1pY2FsczoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciJ9CgppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3d3dy5jZGMuZ292L3RvYmFjY28vYmFzaWNfaW5mb3JtYXRpb24vZS1jaWdhcmV0dGVzL2ltYWdlcy9lLWNpZ2FyZXR0ZS1hZXJvc29sLWNhbi1jb250YWluLWhhcm1mdWwtaW5ncmVkaWVudHMtZGVza3RvcC03MDAuanBnIikKYGBgCgojIyMjIFtbc291cmNlXShodHRwczovL3d3dy5jZGMuZ292L3RvYmFjY28vYmFzaWNfaW5mb3JtYXRpb24vZS1jaWdhcmV0dGVzL2ltYWdlcy9lLWNpZ2FyZXR0ZS1hZXJvc29sLWNhbi1jb250YWluLWhhcm1mdWwtaW5ncmVkaWVudHMtZGVza3RvcC03MDAuanBnKV17dGFyZ2V0PSJfYmxhbmsifSAKCkUtY2lnYXJldHRlIHVzYWdlIGhhcyBhbHNvIGJlZW4gYXNzb2NpYXRlZCB3aXRoIFtsdW5nIGluanVyeV0oKGh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9hcnRpY2xlcy8xMC4zMzg5L2ZwaGFyLjIwMTkuMDE2MTkvZnVsbCkpe3RhcmdldD0iX2JsYW5rIn06CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiODAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJsdW5nLnBuZyIpKQpgYGAKCiMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9hcnRpY2xlcy8xMC4zMzg5L2ZwaGFyLjIwMTkuMDE2MTkvZnVsbClde3RhcmdldD0iX2JsYW5rIn0gCgpTZWUgW2hlcmVdKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9iYXNpY19pbmZvcm1hdGlvbi9lLWNpZ2FyZXR0ZXMvUXVpY2stRmFjdHMtb24tdGhlLVJpc2tzLW9mLUUtY2lnYXJldHRlcy1mb3ItS2lkcy1UZWVucy1hbmQtWW91bmctQWR1bHRzLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gZm9yIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHBvdGVudGlhbCBoZWFsdGggZWZmZWN0cyBvZiBlLWNpZ2FyZXR0ZXMgaW4gdGVlbnMgYW5kIHlvdW5nIGFkdWx0cy4KCiMjICoqTGltaXRhdGlvbnMqKgoqKiogClRoZXJlIGFyZSBzb21lIGltcG9ydGFudCBjb25zaWRlcmF0aW9ucyByZWdhcmRpbmcgdGhpcyBkYXRhIGFuYWx5c2lzIHRvIGtlZXAgaW4gbWluZDogCgoxKSBUaGUgW05hdGlvbmFsIFlvdXRoIFRvYmFjY28gU3VydmV5IChOWVRTKV0oaHR0cHM6Ly93d3cuY2RjLmdvdi90b2JhY2NvL2RhdGFfc3RhdGlzdGljcy9zdXJ2ZXlzL255dHMvaW5kZXguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9IGRvZXMgbm90IGZvbGxvdyB0aGUgc2FtZSBpbmRpdmlkdWFsIHN0dWRlbnQgcmVzcG9uZGVudHMgb3ZlciB0aW1lLiAgQSBbbG9uZ2l0dWRpbmFsIHN0dWR5XShodHRwczovL3d3dy5ibWouY29tL2Fib3V0LWJtai9yZXNvdXJjZXMtcmVhZGVycy9wdWJsaWNhdGlvbnMvZXBpZGVtaW9sb2d5LXVuaW5pdGlhdGVkLzctbG9uZ2l0dWRpbmFsLXN0dWRpZXMpe3RhcmdldD0iX2JsYW5rIn0gdGhhdCBkb2VzIGZvbGxvdyB0aGUgc2FtZSBpbmRpdmlkdWFscyBvdmVyIHRpbWUgY29sbGVjdHMgZGF0YSBjYWxsZWQgW3BhbmVsIGRhdGFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BhbmVsX2RhdGEpe3RhcmdldD0iX2JsYW5rIn0uIFRoZSBkYXRhIGluIHRoaXMgc3R1ZHkgaXMgY2FsbGVkIHBvb2xlZCBbY3Jvc3Mtc2VjdGlvbmFsIGRhdGFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXNlY3Rpb25hbF9kYXRhKXt0YXJnZXQ9Il9ibGFuayJ9LCBhbmQgaXMgb2J0YWluZWQgZnJvbSByYW5kb20gY29sbGVjdGlvbiBvZiBvYnNlcnZhdGlvbnMgYWNyb3NzIHRpbWUuCgpBY2NvcmRpbmcgdG8gV2lraXBlZGlhOgoKPiBQYW5lbCBkYXRhIGRpZmZlcnMgZnJvbSBwb29sZWQgY3Jvc3Mtc2VjdGlvbmFsIGRhdGEgYWNyb3NzIHRpbWUsIGJlY2F1c2UgaXQgZGVhbHMgd2l0aCB0aGUgb2JzZXJ2YXRpb25zIG9uIHRoZSBzYW1lIHN1YmplY3RzIGluIGRpZmZlcmVudCB0aW1lcyB3aGVyZWFzIHRoZSBsYXR0ZXIgb2JzZXJ2ZXMgZGlmZmVyZW50IHN1YmplY3RzIGluIGRpZmZlcmVudCB0aW1lIHBlcmlvZHMKCjIpIFRoZSBkYXRhIGluY2x1ZGUgcGVyY2VudGFnZXMgb2Ygc3R1ZGVudCByZXNwb25kZW50cyByZXBvcnRpbmcgdXNlIG9mIGVhY2ggcGFydGljdWxhciB0b2JhY2NvIHByb2R1Y3QsIGJ1dCB0aGUgc3VydmV5IHF1ZXN0aW9ucyBkaWQgbm90IGFzayB0aGUgcmVsYXRpdmUgYW1vdW50IG9mIHVzZSBvZiBvbmUgcHJvZHVjdCBjb21wYXJlZCB0byBhbm90aGVyLiBGb3IgZXhhbXBsZSB0aGUgc3VydmV5IGluY2x1ZGVkIHF1ZXN0aW9ucyBsaWtlOiJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IiBidXQgZGlkIG5vdCBhc2sgaG93IG9mdGVuIG9uZSBmbGF2b3Igd2FzIHVzZWQgYnkgdGhlIHNhbWUgaW5kaXZpZHVhbCBvdmVyIGFub3RoZXIuCgpXaGlsZSBbZ2VuZGVyXShodHRwczovL3d3dy5nZW5kZXJzcGVjdHJ1bS5vcmcvcXVpY2stbGlua3MvdW5kZXJzdGFuZGluZy1nZW5kZXIvKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBbc2V4XShodHRwczovL3d3dy53aG8uaW50L2dlbm9taWNzL2dlbmRlci9lbi9pbmRleDEuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBhcmUgbm90IGFjdHVhbGx5IGJpbmFyeSwgdGhlIGRhdGEgdXNlZCBpbiB0aGlzIGFuYWx5c2lzIG9ubHkgY29udGFpbiBpbmZvcm1hdGlvbiBmb3IgZ3JvdXBzIG9mIGluZGl2aWR1YWxzIHdobyBhbnN3ZXJlZCB0aGUgc3VydmV5IHF1ZXN0aW9ucyBhcyBtYWxlIG9yIGZlbWFsZS4gCgojIyAqKldoYXQgYXJlIHRoZSBkYXRhPyoqCioqKiAKIApUaGUgZGF0YSBpbiB0aGlzIGNhc2Ugc3R1ZHkgY29tZXMgZnJvbSB0aGUgW05hdGlvbmFsIFlvdXRoIFRvYmFjY28gU3VydmV5IChOWVRTKV0oaHR0cHM6Ly93d3cuY2RjLmdvdi90b2JhY2NvL2RhdGFfc3RhdGlzdGljcy9zdXJ2ZXlzL255dHMvaW5kZXguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9IHdoaWNoIGlzIGFuIGFubnVhbCBzdXJ2ZXkgdGhhdCBhc2tzIHN0dWRlbnRzIGluIGhpZ2ggc2Nob29sIGFuZCBtaWRkbGUgc2Nob29sIChncmFkZXMgNi0xMikgYWJvdXQgdG9iYWNjbyB1c2FnZSBpbiB0aGUgVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhLgoKVGhlIGRhdGEgZm9yIHRoaXMgc3VydmV5IGlzIGZyZWVseSBhdmFpbGFibGUgb25saW5lIGF0IHRoaXMgW3dlYnNpdGVdKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9kYXRhX3N0YXRpc3RpY3Mvc3VydmV5cy9ueXRzL2RhdGEvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB3aXRoIGRhdGEgZnJvbSAxOTk5LCAyMDAwLCAyMDAyLCAyMDA0LCAyMDA2LCAyMDA5LCAgYW5kIDIwMTEtMjAxOS4gV2Ugd2lsbCBiZSB1c2luZyBkYXRhIGZyb20gKioyMDE1LTIwMTkqKiBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGVzZSB5ZWFycyBhcmUgdGhlIG1vc3QgcmVjZW50IHRoYXQgYXNrZWQgcXVlc3Rpb25zIHJlZ2FyZGluZyBlLWNpZ2FyZXR0ZSB1c2FnZS4KCkVhY2ggeWVhciBpbmNsdWRlcyBkb2N1bWVudGF0aW9uLCBzdWNoIGFzIGEgW2NvZGVib29rXShodHRwczovL3d3dy5saWIubmNzdS5lZHUvZGF0YS9pY3BzcmZhcSN3aGF0YXJlKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBhbiBleGNlbCBmaWxlIGNvbnRhaW5pbmcgdGhlIGRhdGE6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiNjAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJkYXRhLnBuZyIpKQpgYGAKVGhlcmVmb3JlLCBzaW5jZSB3ZSBhcmUgdXNpbmcgZGF0YSBmcm9tICoqMjAxNS0yMDE5KiosIHRoZSBkYXRhIHdlIGFyZSBpbnRlcmVzdGVkIGluIGFyZSBsb2NhdGVkIGluIDUgZGlmZmVyZW50IGV4Y2VsIGZpbGVzLCBvbmUgZm9yIGVhY2ggeWVhciwgZWFjaCB3aXRoIGl0cyBvd24gW2NvZGVib29rXSguL2RvY3MvMjAxOS1ueXRzLWRhdGFzZXQtYW5kLWNvZGVib29rLW1pY3Jvc29mdC1leGNlbC8yMDE5LW55dHMtY29kZWJvb2stcC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gKHRoaXMgaXMgdGhlIG9uZSBmb3IgMjAxOSkuCgpUaGUgW2NvZGVib29rXShodHRwczovL3d3dy5pY3Bzci51bWljaC5lZHUvaWNwc3J3ZWIvY29udGVudC9zaGFyZWQvSUNQU1IvZmFxcy93aGF0LWlzLWEtY29kZWJvb2suaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBjb250YWlucyBpbmZvcm1hdGlvbiBkZXNjcmliaW5nIHRoZSBkYXRhIHdpdGhpbiB0aGUgZXhjZWwgZmlsZS4gCgpBcyB5b3UgY2FuIHNlZSB0aGUgZXhjZWwgZmlsZSBjb250YWlucyB2ZXJ5IHNob3J0IHZhcmlhYmxlIG5hbWVzIGFuZCBudW1lcmljIHZhbHVlcywgYW5kIGl0IGlzIG5vdCBjbGVhciB3aGF0IHRoZXkgbWVhbiB3aXRob3V0IHRoZSBjb2RlYm9vazoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciIsIG91dC53aWR0aCA9ICI2MDAgcHgifQoKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImV4Y2VsLnBuZyIpKQpgYGAKClRoZSBjb2RlYm9vayBleHBsYWlucyB3aGF0IHRoZSB2YXJpYWJsZXMgKHRoZSBjb2x1bW5zKSBhcmU6CmBgYHtyLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciIsIG91dC53aWR0aCA9ICI2MDAgcHgifQoKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInZhcmlhYmxlcy5wbmciKSkKYGBgCgpBbmQgdGhlIGNvZGVib29rIGV4cGxhaW5zIHdoYXQgdGhlIHZhbHVlcyBmb3IgZWFjaCB2YXJpYWJsZSBhcmU6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiNjAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJxbjEucG5nIikpCmBgYAoKV2Ugd2lsbCBleHBsYWluIG1vcmUgbGF0ZXIgYWJvdXQgd2hhdCB0aGUgdmFsdWVzIG9uIHRoZSByaWdodCBpbmRpY2F0ZS4KClRoZSByZWFzb24gdGhhdCB0aGVyZSBhcmUgY29kZWJvb2tzIGZvciBlYWNoIHllYXIgaXMgYmVjYXVzZSB0aGUgcXVlc3Rpb25zIGFza2VkIGVhY2ggeWVhciB2YXJpZWQgc2xpZ2h0bHkuCgoKVGhlIGRhdGEgaW4gdGhpcyBzdXJ2ZXkgYXJlIHBvb2xlZCBjcm9zcy1zZWN0aW9uYWwgZGF0YS4gSW4gdGhpcyBzdHVkeSBkZXNpZ24sIGRpZmZlcmVudCBzdWJzZXRzIG9mIHN0dWRlbnQgcmVzcG9uZGVudHMgYXJlIHN1cnZleWVkIGVhY2ggeWVhciBhbmQgaXQgaXMgbm90IGNsZWFyIHdoaWNoLCBpZiBhbnksIGluZGl2aWR1YWxzIHBhcnRpY2lwYXRlIG1vcmUgdGhhbiBvbmNlIGZyb20gb25lIHllYXIgdG8gdGhlIG5leHQuCgojIyAqKkRhdGEgSW1wb3J0KioKKioqIAoKIyMjICoqUmVhZGluZyBpbiB0aGUgZXhjZWwgZmlsZXMqKgoqKioKU2luY2UgdGhlc2UgZXhjZWwgZmlsZXMgYXJlIHNvIGxhcmdlIChlYWNoIGhhcyByb3VnaGx5IDIwLDAwMCByb3dzKSwgaXQgdGFrZXMgYSBiaXQgb2YgdGltZSBmb3IgdGhlIGRhdGEgdG8gbG9hZC4gVG8gbWFrZSB0aGUgcHJvY2VzcyBmYXN0ZXIsIHdlIHByZXZpb3VzbHkgaW1wb3J0ZWQgdGhlc2UgZmlsZXMsIHNlbGVjdGVkIG9ubHkgdGhlIGNvbHVtbnMgcmVsZXZhbnQgdG8gb3VyIHF1ZXN0aW9ucyBvZiBpbnRlcmVzdCwgYW5kIHNhdmVkIHRoZXNlIGRhdGEgc3Vic2V0cyBhcyBjb21tYS1zZXBhcmF0ZWQgKC5jc3YpIGZpbGVzLiAKCjxkZXRhaWxzPjxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBkZXRhaWxzIG9uIGhvdyB0aGUgZGF0YSB3ZXJlIG9yaWdpbmFsbHkgaW1wb3J0ZWQgPC9zdW1tYXJ5PgoKRmlyc3Qgd2UgY3JlYXRlZCBhIHZlY3RvciBvZiBmaWxlIG5hbWVzIG9mIGFsbCB0aGUgZGlmZmVyZW50IGV4Y2VsIGZpbGVzLiBVc2luZyB0aGUgYGhlcmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBoZXJlYCBwYWNrYWdlLCB3ZSBsb29rZWQgaW4gYWxsIHRoZSBkaXJlY3RvcmllcyBvZiB0aGUgcHJvamVjdC4KVGhlIGBsaXN0LmZpbGVzKClgIGZ1bmN0aW9uIGxvb2tlZCBmb3IgYWxsIGZpbGVzIHdpdGggLnhsc3ggd2l0aGluIHRoZXNlIHN1Yi1kaXJlY3Rvcmllcy4KYGBge3J9CmV4Y2VsX2ZpbGVzIDwtIGxpc3QuZmlsZXMoaGVyZTo6aGVyZSgpLCByZWN1cnNpdmUgPSBUUlVFLAogICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIioueGxzeCIpCmV4Y2VsX2ZpbGVzCmBgYAoKQWxsIHRoZSBmaWxlcyB3ZXJlIHJlYWQgdXNpbmcgYHJlYWRfZXhjZWwoKWAgb2YgdGhlIGByZWFkeGxgIHBhY2thZ2UuIFVzaW5nIHRoZSBgbWFwKClgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2UgdGhpcyB3YXMgZG9uZSBlZmZpY2llbnRseSBmb3IgYWxsIG9mIHRoZSBleGNlbCBmaWxlcyBpbiB0aGUgdmVjdG9yIHVzaW5nIG9uZSBjb21tYW5kLiBUaGUgYC5gIGlzIHVzZWQgdG8gaW5kaWNhdGUgdGhhdCB3ZSB3YW50IHRvIGFwcGx5IHRoZSBgcmVhZF9leGNlbCgpYCBmdW5jdGlvbiB0byBlYWNoIGVsZW1lbnQgb2YgdGhlIGRhdGEgdGhhdCB3ZSBqdXN0IHBpcGVkIGludG8gdGhlIGBtYXAoKWAgZnVuY3Rpb24uCgpIZXJlIHdlIGFsc28gdXNlZCB0aGUgYCU+JWAgcGlwZSB3aGljaCBjYW4gYmUgdXNlZCB0byBwYXNzIHRoZSBpbnB1dCBmcm9tIG9uZSBmdW5jdGlvbiB0byBhbm90aGVyIGZvciBsYXRlciBzZXF1ZW50aWFsIHN0ZXBzLiAKClRoaXMgY3JlYXRlZCBhIHNpbmdsZSBsaXN0IG9mIHRpYmJsZXMgKG9uZSBmb3IgZWFjaCBmaWxlKS4gCmBgYHtyLCBldmFsID0gRkFMU0V9CnRibF9maWxlcyA8LSBleGNlbF9maWxlcyAlPiUKICAgICAgIG1hcCh+IHJlYWR4bDo6cmVhZF9leGNlbCguKSkKYGBgCgpUaGUgZWxlbWVudHMgb2YgdGhpcyBsaXN0IGFyZSBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgZWxlbWVudHMgb2YgdGhlIGBleGNlbF9maWxlc2AgdmVjdG9yLCBzbyB3ZSBjYW4gZXh0cmFjdCB0aGUgZGF0YSBmb3IgYSBwYXJ0aWN1bGFyIGZpbGUgKHllYXIpIGJ5IHNlbGVjdGluZyBhIGNlcnRhaW4gZWxlbWVudCBvZiB0aGUgbGlzdC4gSG93ZXZlciwgaXQgaXMgc2FmZXIgdG8gYmUgYWJsZSB0byBzZWxlY3QgdGhlIGRhdGEgZnJvbSB0aGlzIGxpc3QgZm9yIGEgc3BlY2lmaWMgeWVhciB1c2luZyBhIG5hbWUgYmFzZWQgb24gdGhlIG9yaWdpbmFsIHZlY3RvciBvZiBmaWxlIG5hbWVzLiBXZSBleHRyYWN0ZWQgYSBuYW1lIGZyb20gZWFjaCBFeGNlbCBmaWxlIG5hbWUgdXNpbmcgdGhlIGBzdHJfZXh0cmFjdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIEhlcmUgd2UgYXJlIGtlZXBpbmcgb2NjdXJyZW5jZXMgb2YgdGhlIGNoYXJhY3RlciBzdHJpbmcgIm55dHMyMDEiIGZvbGxvd2VkIGJ5IGEgIjUiLCI2IiwiNyIsIjgiLCBvciAiOSIuCgpgYGB7cn0KdGJsX25hbWVzIDwtIGV4Y2VsX2ZpbGVzICU+JQogIHN0cl9leHRyYWN0KCJueXRzMjAxWzUtOV0iKQoKdGJsX25hbWVzCmBgYAoKVGhlc2UgbmFtZXMgYmVjYW1lIHRoZSBuYW1lcyBvZiB0aGUgdGliYmxlcyBpbiB0aGUgbGlzdCBvZiB0aWJibGVzLgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpuYW1lcyh0YmxfZmlsZXMpIDwtIHRibF9uYW1lcwpgYGAKCgpTcGVjaWZpYyBjb2x1bW5zIHdlcmUgc2VsZWN0ZWQgdXNpbmcgdGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYCBmcm9tIGVhY2ggb2YgdGhlIHRpYmJsZXMgdXNpbmcgdGhlIHZhcmlhYmxlIG5hbWUsIGFzIGlkZW50aWZpZWQgaW4gdGhlIGNvZGVib29rIGFzIGJlaW5nIG9mIGludGVyZXN0IGZvciBvdXIgYW5hbHlzaXMuCkluIHNvbWUgY2FzZXMgZnVuY3Rpb25zIGxpa2UgYHN0YXJ0c193aXRoKClgIG9mIHRoZSBgZHBseXJgIHBhY2thZ2Ugd2VyZSB1c2VkIHRvIHNlbGVjdCBzZXZlcmFsIHZhcmlhYmxlcyBhdCBvbmNlLiBNb3N0IG9mIHRoZSBzdXJ2ZXkgcXVlc3Rpb25zIGFib3V0IHRvYmFjY28gdXNlIHN0YXJ0IHdpdGggYW4gYCJFImAgb3IgYSBgIkMiYCBhY2NvcmRpbmcgdG8gdGhlIGNvZGVib29rcy4gCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQoKdGJsX2ZpbGVzW1sibnl0czIwMTUiXV0gPC0gdGJsX2ZpbGVzW1sibnl0czIwMTUiXV0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KHBzdSwgIyBQcmltYXJ5IFNhbXBsaW5nIFVuaXQKICAgICAgICAgICAgICAgICAgZmlud2d0LCAjIEFuYWx5c2lzIFdlaWdodAogICAgICAgICAgICAgICAgICBzdHJhdHVtLCAjIFNhbXBsaW5nIHN0cmF0dW0KICAgICAgICAgICAgICAgICAgUW4xLCAjIEFnZQogICAgICAgICAgICAgICAgICBRbjIsICMgU2V4CiAgICAgICAgICAgICAgICAgIFFuMywgIyBHcmFkZQogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICApCgoKdGJsX2ZpbGVzW1sibnl0czIwMTYiXV0gPC0gdGJsX2ZpbGVzW1sibnl0czIwMTYiXV0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KHBzdSwKICAgICAgICAgICAgICAgICAgZmlud2d0LAogICAgICAgICAgICAgICAgICBzdHJhdHVtLAogICAgICAgICAgICAgICAgICBRMSwgIyBBZ2UKICAgICAgICAgICAgICAgICAgUTIsICMgU2V4CiAgICAgICAgICAgICAgICAgIFEzLCAjIEdyYWRlCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIFE1MEEsICMgTWVudGhvbCAjIFdoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKFNlbGVjdCBvbmUgb3IgbW9yZSkKICAgICAgICAgICAgICAgICAgUTUwQiwgIyBDbG92ZSBvciBzcGljZQogICAgICAgICAgICAgICAgICBRNTBDLCAjIEZydWl0CiAgICAgICAgICAgICAgICAgIFE1MEQsICMgQ2hvY29sYXRlCiAgICAgICAgICAgICAgICAgIFE1MEUsICMgQWxjb2hvbGljIERyaW5rCiAgICAgICAgICAgICAgICAgIFE1MEYsICMgQ2FuZHkvRGVzc2VydHMvT3RoZXIgU3dlZXRzCiAgICAgICAgICAgICAgICAgIFE1MEcgIyBTb21lIE90aGVyIEZsYXZvciBOb3QgTGlzdGVkIEhlcmUKICAgICAgICAgICAgICAgICAgKQoKdGJsX2ZpbGVzW1sibnl0czIwMTciXV0gPC0gdGJsX2ZpbGVzW1sibnl0czIwMTciXV0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KHBzdSwKICAgICAgICAgICAgICAgICAgZmlud2d0LAogICAgICAgICAgICAgICAgICBzdHJhdHVtLAogICAgICAgICAgICAgICAgICBRMSwgIyBBZ2UKICAgICAgICAgICAgICAgICAgUTIsICMgU2V4CiAgICAgICAgICAgICAgICAgIFEzLCAjIEdyYWRlCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgIFE1MEEsICMgTWVudGhvbCAjIFdoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKFNlbGVjdCBvbmUgb3IgbW9yZSkKICAgICAgICAgICAgICAgICAgUTUwQiwgIyBDbG92ZSBvciBzcGljZQogICAgICAgICAgICAgICAgICBRNTBDLCAjIEZydWl0CiAgICAgICAgICAgICAgICAgIFE1MEQsICMgQ2hvY29sYXRlCiAgICAgICAgICAgICAgICAgIFE1MEUsICMgQWxjb2hvbGljIERyaW5rCiAgICAgICAgICAgICAgICAgIFE1MEYsICMgQ2FuZHkvRGVzc2VydHMvT3RoZXIgU3dlZXRzCiAgICAgICAgICAgICAgICAgIFE1MEcgICMgU29tZSBPdGhlciBGbGF2b3IgTm90IExpc3RlZCBIZXJlCiAgICAgICAgICAgICAgICAgICkKCnRibF9maWxlc1tbIm55dHMyMDE4Il1dIDwtIHRibF9maWxlc1tbIm55dHMyMDE4Il1dICU+JQogICAgZHBseXI6OnNlbGVjdChwc3UsCiAgICAgICAgICAgICAgICAgIGZpbndndCwKICAgICAgICAgICAgICAgICAgc3RyYXR1bSwKICAgICAgICAgICAgICAgICAgUTEsICMgQWdlCiAgICAgICAgICAgICAgICAgIFEyLCAjIFNleAogICAgICAgICAgICAgICAgICBRMywgIyBHcmFkZQogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBRNTBBLCAjIE1lbnRob2wgI1doYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKFNlbGVjdCBvbmUgb3IgbW9yZSkKICAgICAgICAgICAgICAgICAgUTUwQiwgIyBDbG92ZSBvciBzcGljZQogICAgICAgICAgICAgICAgICBRNTBDLCAjIEZydWl0CiAgICAgICAgICAgICAgICAgIFE1MEQsICMgQ2hvY29sYXRlCiAgICAgICAgICAgICAgICAgIFE1MEUsICMgQWxjb2hvbGljIERyaW5rCiAgICAgICAgICAgICAgICAgIFE1MEYsICMgQ2FuZHkvRGVzc2VydHMvT3RoZXIgU3dlZXRzCiAgICAgICAgICAgICAgICAgIFE1MEcgICMgU29tZSBPdGhlciBGbGF2b3IgTm90IExpc3RlZCBIZXJlCiAgICAgICAgICAgICAgICAgICkKCnRibF9maWxlc1tbIm55dHMyMDE5Il1dIDwtIHRibF9maWxlc1tbIm55dHMyMDE5Il1dICU+JQogICAgZHBseXI6OnNlbGVjdChwc3UsCiAgICAgICAgICAgICAgICAgIGZpbndndCwKICAgICAgICAgICAgICAgICAgc3RyYXR1bSwKICAgICAgICAgICAgICAgICAgUTEsICMgQWdlCiAgICAgICAgICAgICAgICAgIFEyLCAjIFNleAogICAgICAgICAgICAgICAgICBRMywgIyBHcmFkZQogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICBRNDAsICMgQnJhbmQsIGUtY2lnYXJldHRlcwogICAgICAgICAgICAgICAgICBRNjJBLCAjIE1lbnRob2wgIyBXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChTZWxlY3Qgb25lIG9yIG1vcmUpCiAgICAgICAgICAgICAgICAgIFE2MkIsICMgQ2xvdmUgb3Igc3BpY2UKICAgICAgICAgICAgICAgICAgUTYyQywgIyBGcnVpdAogICAgICAgICAgICAgICAgICBRNjJELCAjIENob2NvbGF0ZQogICAgICAgICAgICAgICAgICBRNjJFLCAjIEFsY29ob2xpYyBEcmluawogICAgICAgICAgICAgICAgICBRNjJGLCAjIENhbmR5L0Rlc3NlcnRzL090aGVyIFN3ZWV0cwogICAgICAgICAgICAgICAgICBRNjJHLCAjIFNvbWUgT3RoZXIgRmxhdm9yIE5vdCBMaXN0ZWQgSGVyZQogICAgICAgICAgICAgICAgICApCmBgYAoKQSBkaXJlY3RvcnkgY2FsbGVkIGBkYXRhX3JlZHVjZWRgIHdhcyBjcmVhdGVkIGZvciB0aGUgbmV3IC5jc3YgZmlsZXMgdXNpbmcgdGhlIGJhc2UgYGRpci5jcmVhdGUoKWAgZnVuY3Rpb24uIApBIGNzdiBmaWxlIHdhcyBjcmVhdGVkIGZvciBlYWNoIG9mIHRoZSB0aWJibGVzIGluIHRoZSBsaXN0IHVzaW5nIHRoZSBgd3JpdGVfY3N2KClgIGZ1bmN0aW9uIG9mIHRoZSBgcmVhZHJgIHBhY2thZ2UuClRoaXMgd2FzIGRvbmUgYWxsIGF0IG9uY2UgdXNpbmcgdGhlIGBtYXAoKWAgZnVuY3Rpb24uCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojCmRpci5jcmVhdGUoImRhdGEvZGF0YV9yZWR1Y2VkIikKCm5hbWVzKHRibF9maWxlcykgJT4lIG1hcCh+IHdyaXRlX2Nzdih0YmxfZmlsZXNbWy5dXSwgcGF0aCA9IHBhc3RlMCgiZGF0YS9kYXRhX3JlZHVjZWQvIiwgLiwgIi5jc3YiKSkpCmBgYAoKPC9kZXRhaWxzPgoKCgpOb3cgd2Ugd2lsbCBzaG93IGhvdyB0byByZWFkIGluIHRoZSBkYXRhIGZyb20gdGhlIGZpdmUgY3N2IGZpbGVzIHRoYXQgd2VyZSBjcmVhdGVkIGZyb20gdGhlIGZpdmUgZGlmZmVyZW50IEV4Y2VsIGZpbGVzLgoKIyMjICoqUmVhZGluZyBpbiB0aGUgQ1NWIGZpbGVzKioKKioqCgoKYGBge3J9Cm55dHNfZGF0YSA8LSBsaXN0LmZpbGVzKGhlcmU6OmhlcmUoKSwgcmVjdXJzaXZlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKi5jc3YiKSAlPiUKICBtYXAofiByZWFkX2NzdiguKSkKCgpueXRzX2RhdGFfbmFtZXMgPC0gbGlzdC5maWxlcyhyZWN1cnNpdmUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIqLmNzdiIpICU+JQogIHN0cl9leHRyYWN0KCJueXRzMjAxWzUtOV0iKQoKbmFtZXMobnl0c19kYXRhKSA8LSBueXRzX2RhdGFfbmFtZXMKYGBgCgoKIyMgKipEYXRhIEV4cGxvcmF0aW9uIGFuZCBXcmFuZ2xpbmcqKgoqKiogCgpPdXIgZ29hbCBpbiB0aGlzIHNlY3Rpb24gaXMgdG8gYWRqdXN0IG9yICJ3cmFuZ2xlIiB0aGUgZGF0YSBmcm9tIGVhY2ggeWVhciBpbnRvIGEgY29tbW9uIGZvcm1hdCBzbyB0aGF0IHdlIGNhbiBjb21iaW5lIHRoZSBkYXRhIHNldHMgYWNyb3NzIHllYXJzIGZvciBvdXIgYW5hbHlzaXMsIGFuZCBzbyB0aGF0IHdlIGhhdmUgdmFsdWVzIGluIG91ciB2YXJpYWJsZXMgdGhhdCBhcmUgY29ycmVjdCBhbmQgZWFzeSB0byBpbnRlcnByZXQuIFdlIHdpbGwgbmVlZCB0byB1bmRlcnN0YW5kIHdoYXQgaXMgdGhlIHNhbWUgYW5kIHdoYXQgaXMgZGlmZmVyZW50IGFjcm9zcyB0aGUgZGF0YSBmcm9tIGRpZmZlcmVudCB5ZWFycywgcmVuYW1lIGFuZCByZWNvZGUgdGhlIHZhcmlhYmxlcyAoZS5nLiwgYnkgcmVwbGFjaW5nIHRoZSBudW1iZXJzIDEgYW5kIDIgd2l0aCB0aGUgdmFsdWVzICJNYWxlIiBhbmQgIkZlbWFsZSIgZm9yIHRoZSBgU2V4YCB2YXJpYWJsZSksIGFuZCBjb21iaW5lIHRoZSBkYXRhLiBXZSB3aWxsIHdhbGsgdGhyb3VnaCB0aGVzZSBzdGVwcyBiZWxvdy4gCgpGaXJzdCwgbGV0J3MgdGFrZSBhIGxvb2sgYXQgb3VyIGRhdGEuIFdlIGNhbiBnZXQgYSBnb29kIHNlbnNlIG9mIGl0IHVzaW5nIHRoZSBgZ2xpbXBzZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLgoKIyMjIyB7LnNjcm9sbGFibGUgfQoKYGBge3J9CmRwbHlyOjpnbGltcHNlKG55dHNfZGF0YVtbIm55dHMyMDE1Il1dKQpgYGAKIyMjIwoKIyMjICoqVXBkYXRpbmcgdGhlIHNldCBvZiB2YXJpYWJsZXMgYW5kIHRoZWlyIG5hbWVzKioKKioqIAoKVGhlIGVhc2llc3Qgd2F5IG9mIG1ha2luZyBpdCBzbyB0aGF0IHRoZSBkYXRhIGZyb20gdGhlIGRpZmZlcmVudCB5ZWFycyBjYW4gYmUgY29tYmluZWQgaXMgYnkgbWFraW5nIHN1cmUgdGhhdCB0aGUgc2FtZSB0eXBlIG9mIGRhdGEgaW4gZGlmZmVyZW50IGRhdGFzZXRzIHNoYXJlIHRoZSBzYW1lIG5hbWVzLiBJbiBhZGRpdGlvbiwgZ2l2aW5nIHRoZSBjb2x1bW5zIGluZm9ybWF0aXZlIG5hbWVzIHdpbGwgaGVscCBtYWtlIG91ciBjb2RlIG1vcmUgcmVhZGFibGUuIEN1cnJlbnRseSwgaXQgaXNuJ3QgdmVyeSBjbGVhciB3aGF0IG1vc3Qgb2YgdGhlIHZhcmlhYmxlcyBpbmRpY2F0ZSBzaW5jZSB0aGUgdmFyaWFibGUgbmFtZXMgYXJlIHVuaW5mb3JtYXRpdmUgb24gdGhlaXIgb3duLCB3aXRob3V0IHRoZSBbY29kZWJvb2tdKC4vZG9jcy8yMDE5LW55dHMtZGF0YXNldC1hbmQtY29kZWJvb2stbWljcm9zb2Z0LWV4Y2VsLzIwMTktbnl0cy1jb2RlYm9vay1wLnBkZil7dGFyZ2V0PSJfYmxhbmsifS4KCldlIHdhbnQgdG8gcmVuYW1lIHZhcmlhYmxlcyBsaWtlIGBRbjFgIHRvIHNvbWV0aGluZyBtb3JlIG1lYW5pbmdmdWwgbGlrZSBgQWdlYC4KClRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGByZW5hbWUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gVGhlIG5ldyBuYW1lIGlzIGFsd2F5cyBsaXN0ZWQgZmlyc3QgYmVmb3JlIHRoZSBgPWAuIFRoaXMgZnVuY3Rpb24gd2lsbCByZXBsYWNlIHRoZSBvbGQgdmFyaWFibGUgbmFtZXMgd2l0aCB0aGUgbmV3IG9uZXMsIGkuZS4sIGFmdGVyIHJ1bm5pbmcgdGhlIGNvZGUgYmVsb3csIHRoZXJlIHdpbGwgbm8gbG9uZ2VyIGJlIGEgYFFuMWAgdmFyaWFibGUgaW4gdGhlIGRhdGEgc2V0LCBidXQgdGhlcmUgd2lsbCBiZSBhbiBgQWdlYCB2YXJpYWJsZSBpbnN0ZWFkLiBXZSB3aWxsIHN0YXJ0IHdvcmtpbmcgd2l0aCB0aGUgMjAxNSBkYXRhLCBhbmQgdGhlbiBtb3ZlIG9uIHRvIHRoZSBvdGhlciB5ZWFycyBkb3duIGJlbG93LgoKYGBge3J9CgpueXRzX2RhdGFbWyJueXRzMjAxNSJdXSA8LSBueXRzX2RhdGFbWyJueXRzMjAxNSJdXSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoQWdlID0gUW4xLAogICAgICAgICAgICAgICAgICBTZXggPSBRbjIsCiAgICAgICAgICAgICAgICBHcmFkZSA9IFFuMykKYGBgCgoKClVsdGltYXRlbHkgd2Ugd2lsbCBiZSBjb21iaW5pbmcgdGhlIGRhdGEgZnJvbSBlYWNoIHllYXIgdXNpbmcgdGhlIGBiaW5kX3Jvd3MoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSwgd2hpY2ggd2lsbCBmaWxsIGluIGBOQWAgdmFsdWVzIGZvciBhbnkgY29sdW1ucyB0aGF0IGRvIG5vdCBleGlzdCBmb3Igb25lIG9mIHRoZSB5ZWFycy4KClRoZSBkYXRhIGZvciAyMDE2LTIwMTggaGF2ZSBtYW55IGNvbW1vbiBhdHRyaWJ1dGVzLCBzbyB3ZSB3aWxsIHdhbnQgdG8gd3JpdGUgY29kZSB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGFsbCB0aHJlZSBkYXRhIHNldHMuIFRvIGRvIHRoaXMsIHdlIHdpbGwgdXNlIGEgYGZ1bmN0aW9uYCBpbiBSLCB3aGljaCBpcyBiYXNpY2FsbHkgYSBwaWVjZSBvZiBjb2RlIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gc2ltaWxhciBidXQgZGlmZmVyZW50IG9iamVjdHMgaW4gUiAoZS5nLiwgdGhlIGRhdGEgdGliYmxlcyBmcm9tIGVhY2ggb2YgdGhlc2UgdGhyZWUgeWVhcnMpLiBSZWNhbGwgdGhhdCB5b3UgYXJlIHVzaW5nIGZ1bmN0aW9ucyBmcm9tIHBhY2thZ2VzIGFsbCB0aGUgdGltZSwgbGlrZSB0aGUgYHJlbmFtZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBOb3cgeW91IGFyZSBnb2luZyB0byB3cml0ZSB5b3VyIG93biBmdW5jdGlvbiEgRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gZnVuY3Rpb25zLCBzZWUgW2hlcmVdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZnVuY3Rpb25zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgpUaGVzZSBuZXh0IDMgeWVhcnMgaGF2ZSB0aGUgc2FtZSBzdHJ1Y3R1cmUgZm9yIG1hbnkgb2YgdGhlIHF1ZXN0aW9ucyB3ZSBhcmUgaW50ZXJlc3RlZCBpbi4gRm9yIGV4YW1wbGUsIHRoZXkgYWxsIGhhdmUgZmxhdm9yIHF1ZXN0aW9ucywgYnV0IG5vdCBhIGJyYW5kIHF1ZXN0aW9uLiBNb3Jlb3ZlciwgdGhlaXIgdmFyaWFibGUgbmFtZXMgYXJlIGNvbnNpc3RlbnQgYWNyb3NzIHRoZSB5ZWFyczsgZm9yIGVhY2ggeWVhciwgd2Ugd2FudCB0byByZXBsYWNlIHRoZSB2YWd1ZSBxdWVzdGlvbiBuYW1lIGBRNTBBYCB3aXRoIHRoZSB2YWx1ZSBgbWVudGhvbGAgaW4gYWxsIHRocmVlIGRhdGEgc2V0cywgYW5kIHRoZSBzYW1lIGlzIHRydWUgZm9yIHRoZSBvdGhlciBmbGF2b3IgdmFyaWFibGVzLiAgCgpTaW5jZSB3ZSB3YW50IHRvIHBlcmZvcm0gdGhlIHNhbWUgbW9kaWZpY2F0aW9ucyBvbiB0aGUgZGF0YSBmcm9tIGFsbCB0aHJlZSB5ZWFycywgcmF0aGVyIHRoYW4gcmVwZWF0aW5nIHRoZSBzYW1lIHNvbWV3aGF0IG1lc3N5IHBpZWNlIG9mIGNvZGUgdGhyZWUgdGltZXMsIHdlIGNhbiBkbyB0aGlzIG1vcmUgZWZmaWNpZW50bHkgaWYgd2UgY3JlYXRlIGEgZnVuY3Rpb24gdG8gZG8gYWxsIG9mIHRoZXNlIHN0ZXBzIGF0IG9uY2UuIFRoZW4gd2UgY2FuIHVzZSB0aGUgYG1hcF9hdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHB1cnJyYCBwYWNrYWdlLCB3aGljaCBpcyBhbiBleHRlbnNpb24gb2YgdGhlIGBtYXAoKWAgZnVuY3Rpb24gdGhhdCB3ZSB1c2VkIGluIHRoZSBbUmVhZGluZyBpbiB0aGUgZXhjZWwgZmlsZXNdIHNlY3Rpb24gdG8gYXBwbHkgdGhlIGZ1bmN0aW9uIHdlIGp1c3QgY3JlYXRlZCAoZm9yIHJlbmFtaW5nIHZhcmlhYmxlcyBldGMuKSBzcGVjaWZpY2FsbHkgdG8gdGhlIGRhdGEgZnJvbSAyMDE2LTIwMTggd2l0aGluIHRoZSBgbnl0c19kYXRhYC4gQnkgdXNpbmcgYHZhcnMoKWAgaW5zaWRlIG9mIHRoZSBgbWFwX2F0KClgIGZ1bmN0aW9uIHdlIGNhbiBzcGVjaWZ5IHdoYXQgdGliYmxlcyB3aXRoaW4gb3VyIGBueXRzX2RhdGFgIGxpc3Qgd2Ugd2FudCB0byBpbmNsdWRlIG9yIGV4Y2x1ZGUuIAoKClNvIGhvdyBkbyB5b3UgY3JlYXRlIGEgZnVuY3Rpb24/CllvdSBmaXJzdCBuZWVkIHRvIHNwZWNpZnkgdGhhdCB5b3UgYXJlIGNyZWF0aW5nIGEgZnVuY3Rpb24gYnkgdXNpbmcgdGhlIGBmdW5jdGlvbigpYCBiYXNlIGZ1bmN0aW9uLgpZZXMsIHRoYXQncyByaWdodCBpdCBhcyBhIGZ1bmN0aW9uIGZvciBjcmVhdGluZyBmdW5jdGlvbnMgY2FsbGVkIGZ1bmN0aW9uIQoKRmlyc3Qgd2Ugc3BlY2lmeSBvdXIgaW5wdXQgd2l0aGluIHRoZSBwYXJlbnRoZXNlcyBvZiBgZnVuY3Rpb24oKWAuIFRodXMgaWYgb3VyIGZ1bmN0aW9uIHdpbGwgYXBwbHkgc29tZXRoaW5nIHRvIGFuIGlucHV0IGNhbGxlZCBgeGAgdGhlbiB3ZSB3b3VsZCB1c2UgYGZ1bmN0aW9uKHgpYC4gUmVhbGx5IG91ciBpbnB1dCBjYW4gYmUgbmFtZWQgd2hhdGV2ZXIgd2Ugd2FudCwgYnV0IHdlIHdlIG5lZWQgdG8gcmVmZXIgdG8gaXQgY29uc2lzdGVudGx5IHdpdGhpbiBvdXIgZnVuY3Rpb24gdG8gaW5kaWNhdGUgd2hhdCB3ZSB3YW50IGRvbmUgd2l0aCB0aGUgaW5wdXQgZGF0YS4gV2UgY2FuIGFjdHVhbGx5IGhhdmUgbW9yZSB0aGFuIG9uZSBpbnB1dCBhcyB3ZWxsLCB3ZSB3b3VsZCBpbmRpY2F0ZSB0d28gaW5wdXRzIGxpa2UgdGhpczogYGZ1bmN0aW9uKHgsIGIpYC4gSGVyZSB3ZSB3ZSB3b3VsZCBiZSB1c2luZyBib3RoIGB4YCBhbmQgYGJgIHRvIGRvIHNvbWV0aGluZyBpbiBvdXIgZnVuY3Rpb24uCgpUaGUgbmV4dCBwYXJ0IG9mIGEgZnVuY3Rpb24gaXMgd2l0aGluIGRlZmluZWQgd2l0aGluIGN1cmx5IGJyYWNrZXRzIGB7fWAuIFRoaXMgaXMgd2hlcmUgd2Ugd3JpdGUgd2hhdCB3ZSB3YW50IGRvbmUgdG8gb3VyIGlucHV0cy4KCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgYSBzaW1wbGUgZXhhbXBsZSA8L3N1bW1hcnk+IAoKT3VyIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIGBzaW1wbGVfZnVuY3Rpb25gIGFuZCBpdCB3aWxsIHRha2UgdGhlIGlucHV0IGB4YC4gSXQgd2lsbCBhZGQgMiB0byBvdXIgaW5wdXQuCmBgYHtyfQp4ID0gYygxLCAyLCAzLCA0KQp4CnNpbXBsZV9mdW5jdGlvbiA8LSBmdW5jdGlvbih4KSB7CiAgeCArIDIKfQoKc2ltcGxlX2Z1bmN0aW9uKHgpCmBgYAoKVGhlIG5hbWUgb2Ygb3VyIGlucHV0IGRvZXMgbm90IG5lZWQgdG8gbWF0Y2ggbGlrZSBpbiB0aGUgYWJvdmUgZXhhbXBsZS4gSW5zdGVhZCB3ZSBjYW4gdXNlIGFuIGlucHV0IHRoYXQgaXMgYSB2ZWN0b3IgY2FsbGVkIGB5YCwgYW5kIHdlIGNhbiByZXdyaXRlIG91ciBmdW5jdGlvbiB0byB1c2UgYSBtb3JlIGluZm9ybWF0aXZlIGlucHV0IGFyZ3VtZW50IGxpa2UgYHZlY3Rvcl9kYXRhYC4gTm93IHdlIHNwZWNpZnkgdXNpbmcgdGhlIGFyZ3VtZW50IGAgdmVjdG9yX2RhdGEgPWAgdG8gaW5kaWNhdGUgdGhhdCBgeWAgaXMgb3VyIGlucHV0IHRoYXQgd2Ugd2FudCB0byBwZXJmb3JtIHRoZSBmdW5jdGlvbiBvbi4KCmBgYHtyfQp5ID0gYygxLCAyLCAzLCA0KQoKc2ltcGxlX2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHZlY3Rvcl9kYXRhKSB7CiAgdmVjdG9yX2RhdGEgKyAyCn0Kc2ltcGxlX2Z1bmN0aW9uKHZlY3Rvcl9kYXRhID0geSkKYGBgCgo8L2RldGFpbHM+CgpJbiBvdXIgY2FzZSB3ZSB3aWxsIGJlIGFwcGx5aW5nIG91ciBmdW5jdGlvbiB0byB0aGUgdmFyaWFibGUgbmFtZXMgZm9yIHRoZSBkYXRhc2V0IGZvciBlYWNoIHllYXIuIFRodXMgb3VyIGB4YCBpcyB0aGUgZGF0YXNldCBmb3IgZWFjaCB5ZWFyLiBUaGUgb3V0cHV0IG9mIG91ciBmdW5jdGlvbiBpcyB0aGUgcmVzdWx0IG9mIHJlbmFtaW5nIHRoZXNlIHZhcmlhYmxlcyBmb3IgZWFjaCB5ZWFyLiAKCmBgYHtyfQoKVXBkYXRlX3N1cnZleSA8LSBmdW5jdGlvbih4KSB7IHggJT4lCiAgICAgICAgICAgcmVuYW1lKEFnZSA9IFExLAogICAgICAgICAgICAgICAgICBTZXggPSBRMiwKICAgICAgICAgICAgICAgIEdyYWRlID0gUTMsCiAgICAgICAgICAgICAgbWVudGhvbCA9IFE1MEEsCiAgICAgICAgICBjbG92ZV9zcGljZSA9IFE1MEIsCiAgICAgICAgICAgICAgICBmcnVpdCA9IFE1MEMsCiAgICAgICAgICAgIGNob2NvbGF0ZSA9IFE1MEQsCiAgICAgIGFsY29ob2xpY19kcmluayA9IFE1MEUsCiBjYW5keV9kZXNzZXJ0X3N3ZWV0cyA9IFE1MEYsCiAgICAgICAgICAgICAgICBvdGhlciA9IFE1MEcpCn0KCiMgb3B0aW9ucyB0byBhcHBseSB0aGUgZnVuY3Rpb24gdG8gdGhlIGRhdGE6CiMgbnl0c19kYXRhIDwtbnl0c19kYXRhICU+JSBtYXBfYXQodmFycyhueXRzMjAxNiwgbnl0czIwMTcsIG55dHMyMDE4KSwgVXBkYXRlX3N1cnZleSkKbnl0c19kYXRhIDwtIG55dHNfZGF0YSAlPiUgbWFwX2F0KHZhcnMoLW55dHMyMDE1LCAtbnl0czIwMTkpLCBVcGRhdGVfc3VydmV5KQpgYGAKClRoZSBmaW5hbCB5ZWFyLCAyMDE5LCBoYXMgYSBzbGlnaHRseSBkaWZmZXJlbnQgZGF0YSBzdHJ1Y3R1cmUgY29tcGFyZWQgdG8gdGhlc2UgZWFybGllciBkYXRhIHNldHMuIEl0IGFjdHVhbGx5IGhhcyBhIGBicmFuZF9lY2lnYCB2YXJpYWJsZSBhbHJlYWR5IGFuZCBkaWZmZXJlbnQgcXVlc3Rpb24gbnVtYmVycyBjb3JyZXNwb25kIHRvIG91ciBmbGF2b3IgcXVlc3Rpb25zIG9mIGludGVyZXN0LiBTbyB3ZSB3aWxsIHJlbmFtZSB0aGUgdmFyaWFibGVzIGluIHRoaXMgZGF0YSBzZXQgaW5kaXZpZHVhbGx5LiBXZSBjb3VsZCBhbHNvIHdyaXRlIHRoaXMgYXMgYSBmdW5jdGlvbiwgYnV0IHNpbmNlIHdlIGFyZSBvbmx5IGFwcGx5aW5nIHRoaXMgb25lIHRpbWUsIHRoZXJlIGlzIG5vIG5lZWQgdG8uIEZ1bmN0aW9ucyBhcmUgcmVhbGx5IGhlbHBmdWwgZm9yIHJlcGVhdGluZyB0aGUgc2FtZSB0YXNrIHJlcGVhdGVkbHkgdXNpbmcgZGlmZmVyZW50IGRhdGEgaW5wdXRzLgoKYGBge3J9Cm55dHNfZGF0YVtbIm55dHMyMDE5Il1dIDwtIG55dHNfZGF0YVtbIm55dHMyMDE5Il1dICU+JQogICAgcmVuYW1lKGJyYW5kX2VjaWcgPSBRNDAsCiAgICAgICAgICAgICAgICAgIEFnZSA9IFExLAogICAgICAgICAgICAgICAgICBTZXggPSBRMiwKICAgICAgICAgICAgICAgIEdyYWRlID0gUTMsCiAgICAgICAgICAgICAgbWVudGhvbCA9IFE2MkEsCiAgICAgICAgICBjbG92ZV9zcGljZSA9IFE2MkIsCiAgICAgICAgICAgICAgICBmcnVpdCA9IFE2MkMsCiAgICAgICAgICAgIGNob2NvbGF0ZSA9IFE2MkQsCiAgICAgIGFsY29ob2xpY19kcmluayA9IFE2MkUsCiBjYW5keV9kZXNzZXJ0X3N3ZWV0cyA9IFE2MkYsCiAgICAgICAgICAgICAgICBvdGhlciA9IFE2MkcpCmBgYAoKCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdmFyaWFibGUgbmFtZXMgZm9yIGVhY2ggb2YgdGhlIHllYXJzIHVzaW5nIHRoZSBgbWFwYCBmdW5jdGlvbiBmcm9tIGBwdXJycmAuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CgpgYGB7cn0KbWFwKG55dHNfZGF0YSwgbmFtZXMpCmBgYAojIyMjCgpJdCdzIGxvb2tpbmcgYmV0dGVyISBUaGUgZGF0YSB0aGF0IG92ZXJsYXAgYWNyb3NzIHllYXJzIGhhdmUgdGhlIHNhbWUgdmFyaWFibGUgbmFtZXMuCgojIyMgKipVcGRhdGluZyBWYWx1ZXMqKgoqKioKTm93IHRoYXQgd2UgaGF2ZSBtYWRlIHNvbWUgcHJvZ3Jlc3Mgb24gdGhlIHNlbGVjdGlvbiBhbmQgbmFtZXMgb2YgdGhlIHZhcmlhYmxlcyB0aGVtc2VsdmVzLCB3ZSB3aWxsIHdvcmsgb24gdGhlIHZhbHVlcyBjb250YWluZWQgaW4gdGhlIGRpZmZlcmVudCB2YXJpYWJsZXMuCgpXZSBjYW4gc3RhcnQgd2l0aCB1cGRhdGluZyB0aGUgdmFsdWVzIGZvciBgQWdlYCBhbmQgYEdyYWRlYCwgc28gdGhhdCB0aGV5IGFyZSBtb3JlIHVuZGVyc3RhbmRhYmxlLiAKClJlY2FsbCBmcm9tIHRoZSBjb2RlYm9vayBmb3IgdGhpcyB5ZWFyJ3MgZGF0YSBzZXQgdGhhdCBgQWdlYCBpc24ndCBsaXN0ZWQgaW4gdGhlIHdheSBvbmUgbWlnaHQgZXhwZWN0LCBpLmUuLCBpdCBpcyBub3QganVzdCBhIG51bWJlciBvZiB5ZWFycywgYnV0IGEgbnVtZXJpY2FsbHkgdmFsdWVkIGNhdGVnb3JpY2FsIHZhcmlhYmxlLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIiwgb3V0LndpZHRoID0gIjYwMCBweCJ9Cgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicW4xLnBuZyIpKQpgYGAKClRoZSBzYW1lIGlzIHRydWUgZm9yIGBHcmFkZWA6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCBvdXQud2lkdGggPSAiNjAwIHB4In0KCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJncmFkZS5wbmciKSkKYGBgCgoqKlRoaXMgaXMgd2h5IGl0IGlzIHNvIGltcG9ydGFudCB0byBhbHdheXMgY2hlY2sgdGhlIGNvZGVib29rISEqKgoKV2UgYWxzbyAgd2FudCB0byByZXBsYWNlIHRoZSB2YWx1ZSBvZiBgMTlgIGZvciBgQWdlYCB0byBiZSBgIj4xOCJgIGFuZCB0aGUgdmFsdWUgb2YgYDEzYCBmb3IgYEdyYWRlYCB0byBiZSByZXBsYWNlZCB3aXRoIGAiVW5ncmFkZWQvT3RoZXIiYCBBbHNvIGFjY29yZGluZyB0byB0aGUgY29kZWJvb2tzLCBudW1lcmljIHZhbHVlcyBvZiBgMWAgaW5kaWNhdGUgYSBzdXJ2ZXkgYW5zd2VyIG9mIGBGQUxTRWAsIHdoaWxlIGEgdmFsdWUgb2YgYDJgIGluZGljYXRlcyBgVFJVRWAuIGBTZXhgIGFsc28gbmVlZHMgdG8gYmUgcmVjb2RlZC4gSWYgd2UgdGFrZSBhIGxvb2sgYXQgdGhlIGNvZGUgYm9va3MgY2FyZWZ1bGx5IChtYWtlIHN1cmUgeW91IGxvb2sgYXQgdGhlIHF1ZXN0aW9ucyB0aGF0IHdlIHB1bGxlZCwgbm90IHRoZSByZWNvZGVkIHZhbHVlcyksIHdlIHdpbGwgc2VlIHRoYXQgbWFsZXMgYXJlIGluZGljYXRlZCBieSBgMWAgYW5kIGZlbWFsZXMgYXJlIGluZGljYXRlZCBieSBgMmAuIEZpbmFsbHkgc29tZSB2YWx1ZXMgYXJlIGluZGljYXRlZCB3aXRoIGAiKiJgIG9yYCIqKiJgIHdoZW4gdGhleSBhcmUgbWlzc2luZy4gV2Ugd2FudCB0byByZXBsYWNlIHRoZXNlIHdpdGggYE5BYC4KCkxldCdzIGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIG1ha2UgYWxsIHRoZXNlIHVwZGF0ZXMuIFdlIHdpbGwgdXNlIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIG1vZGlmeSB0aGVzZSB2YXJpYWJsZXMuIFRoaXMgZnVuY3Rpb24gY2FuIGFsc28gYmUgdXNlZCB0byBjcmVhdGUgbmV3IHZhcmlhYmxlcy4gV2Ugd2lsbCBhbHNvIHVzZSB0aGUgIGByZWNvZGUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byByZXBsYWNlIHNwZWNpZmljIHZhbHVlcyBvZiBjZXJ0YWluIHZhcmlhYmxlcy4KCmBgYHtyfQpVcGRhdGVfdmFsdWVzIDwtIGZ1bmN0aW9uKHgpIHsgeCAlPiUKICAgICAgbXV0YXRlKEFnZSA9IGFzLm51bWVyaWMoQWdlKSArIDgsCiAgICAgICAgICAgR3JhZGUgPSBhcy5udW1lcmljKEdyYWRlKSArIDUpICU+JQogICAgICBtdXRhdGUoQWdlID0gYXMuZmFjdG9yKEFnZSksCiAgICAgICAgICAgR3JhZGUgPSBhcy5mYWN0b3IoR3JhZGUpLAogICAgICAgICAgICAgU2V4ID0gYXMuZmFjdG9yKFNleCkpICU+JQogICAgICBtdXRhdGUoU2V4ID0gcmVjb2RlKFNleCwKICAgICAgICAgICAgICAgICAgICAgIGAxYCA9ICJtYWxlIiwKICAgICAgICAgICAgICAgICAgICAgIGAyYCA9ICJmZW1hbGUiKQogICAgICAgICApICU+JQogIG11dGF0ZV9hbGwofiByZXBsYWNlKC4sIC4gJWluJSBjKCIqIiwgIioqIiksIE5BKSkgJT4lCiAgbXV0YXRlKEFnZSA9IHJlY29kZShBZ2UsCiAgICAgICAgICAgICAgICAgICAgYDE5YCA9ICI+MTgiKSwKICAgICAgIEdyYWRlID0gcmVjb2RlKEdyYWRlLAogICAgICAgICAgICAgICAgICAgICAgYDEzYCA9ICJVbmdyYWRlZC9PdGhlciIpKSAlPiUKICBtdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiRSIsIGlnbm9yZS5jYXNlID0gRkFMU0UpLAogICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJDIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpLAogICAgICAgICAgICAgIGxpc3QofiByZWNvZGUoLiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYDFgID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYDJgID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC5taXNzaW5nID0gTkEpKSkKfQoKbnl0c19kYXRhIDwtIG55dHNfZGF0YSAlPiUgbWFwKC4sIFVwZGF0ZV92YWx1ZXMpCmBgYAoKCk5vdyBpZiB3ZSB3YW50ZWQgdG8gY2hlY2sgdGhhdCBldmVyeXRoaW5nIGlzIGV4cGVjdGVkIHdlIGNvdWxkIGRvIHNvbWV0aGluZyBsaWtlIHRoaXMgdG8gY2hlY2sgdGhlIGBTZXhgIHZhcmlhYmxlIHVzaW5nIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gSXQgaXMgYWR2aXNhYmxlIHRvIGNoZWNrIHlvdXIgZGF0YSBmcmVxdWVudGx5IHRvIG1ha2Ugc3VyZSB0aGF0IGl0IGlzIGFzIGV4cGVjdGVkIQoKQWNjb3JkaW5nIHRvIHRoZSBjb2RlYm9vaywgd2Ugc2hvdWxkIGhhdmU6ICAKMSkgOCw5NTggbWFsZXMgaW4gMjAxNSAKMikgMTAsNDM4IG1hbGVzIGluIDIwMTYgCjMpIDgsODgxIG1hbGVzIGluIDIwMTcgIAo0KSAxMCwwNjkgbWFsZXMgaW4gMjAxOCAgCjUpIDksODAzIG1hbGVzIGluIDIwMTkgIAoKYGBge3J9CmNvdW50X3NleCA8LSBmdW5jdGlvbih4KSB7eCAlPiUgY291bnQoU2V4KX0Kbnl0c19kYXRhICU+JSBtYXAoLiwgY291bnRfc2V4KQpgYGAKCgpMb29rcyBnb29kIQoKVGhlIHllYXJzICgyMDE2LTIwMTkpIHRoYXQgaGF2ZSBmbGF2b3JzIGFsc28gbmVlZCB0aGUgZmxhdm9yIGRhdGEgdG8gYmUgbG9naWNhbCAobWVhbmluZyBUUlVFIG9yIEZBTFNFKToKCkluIHRoaXMgY2FzZSB3ZSBhbHNvIGFyZSBzZXR0aW5nIG1pc3NpbmcgdmFsdWVzIHRvIGBGQUxTRWAgYmVjYXVzZSB0aGVuIGl0IHRoZSBgVFJVRWAgdmFsdWVzIHdpbGwgcmVwcmVzZW50IHRob3NlIHdobyByZXBvcnRlZCB1c2luZyBhIHNwZWNpZmljIGZsYXZvciBvdXQgb2YgYWxsIHVzZXJzLCByYXRoZXIgdGhhbiB0aG9zZSB0aGF0IHVzZWQgYSBzcGVjaWZpYyBmbGF2b3IgY29tcGFyZWQgdG8gdGhvc2Ugd2hvIHVzZWQgYSBkaWZmZXJlbnQgZmxhdm9yLgoKCmBgYHtyfQpVcGRhdGVfZmxhdm9ycyA8LSBmdW5jdGlvbih4KSB7eCAlPiUKICAgbXV0YXRlX2F0KHZhcnMobWVudGhvbDpvdGhlciksCiAgICAgICAgICAgICAgbGlzdCh+IHJlY29kZSguLAogICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIC5taXNzaW5nID0gRkFMU0UpKSkgfQoKbnl0c19kYXRhICA8LSBueXRzX2RhdGEgICU+JSBtYXBfYXQodmFycygtbnl0czIwMTUpLCBVcGRhdGVfZmxhdm9ycykKYGBgCgoKTm93IHRoZXJlIGFyZSBqdXN0IGEgZmV3IGNoYW5nZXMgbmVlZGVkIHRoYXQgYXJlIHNwZWNpZmljIHRvIDIwMTkuIFNwZWNpZmljYWxseSwgc29tZSBvZiB0aGUgMjAxOSBxdWVzdGlvbnMgdXNlIHRoZSB2YWx1ZXMgIi5OIiwgIi5TIiwgYW5kICIuWiIgdG8gaW5kaWNhdGUgZGlmZmVyZW50IHR5cGVzIG9mIG1pc3NpbmcgZGF0YSAoc2VlIGZvciBleGFtcGxlIFEyIG9mIHRoZSAyMDE5IFtjb2RlYm9va10oLi9kb2NzLzIwMTktbnl0cy1kYXRhc2V0LWFuZC1jb2RlYm9vay1taWNyb3NvZnQtZXhjZWwvMjAxOS1ueXRzLWNvZGVib29rLXAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9KTsgd2UganVzdCB3YW50IHRoZW0gdG8gYmUgcmVwbGFjZWQgd2l0aCBgTkFgIHZhbHVlcy4KCgpgYGB7cn0Kbnl0c19kYXRhW1sibnl0czIwMTkiXV0gPC0gbnl0c19kYXRhW1sibnl0czIwMTkiXV0gJT4lCiAgbXV0YXRlX2FsbCh+IHJlcGxhY2UoLiwgLiAlaW4lIGMoIi5OIiwgIi5TIiwgIi5aIiksIE5BKSkgJT4lCiAgbXV0YXRlKHBzdSA9IGFzLmNoYXJhY3Rlcihwc3UpKSAlPiUKICBtdXRhdGUoYnJhbmRfZWNpZyA9IHJlY29kZShicmFuZF9lY2lnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiT3RoZXIiLCAjIGxldmVscyAxLDggY29tYmluZWQgdG8gYE90aGVyYAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMmAgPSAiQmx1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDNgID0gIkpVVUwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgNGAgPSAiTG9naWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgNWAgPSAiTWFya1RlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA2YCA9ICJOSk9ZIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDdgID0gIlZ1c2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgOGAgPSAiT3RoZXIiKSkKYGBgCgpHcmVhdCEgTm93IG91ciB2YWx1ZXMgZG9uJ3QgbmVlZCB0byBiZSBoYW5kbGVkIGFueSBkaWZmZXJlbnRseSBmb3IgYW55IG9mIHRoZSB5ZWFycywgdGh1cyB3ZSBjYW4gY29tYmluZSB0aGUgZGF0YSBhY3Jvc3MgeWVhcnMuCgpFdmVuIHRob3VnaCB3ZSBoYXZlIGRpZmZlcmVudCBudW1iZXJzIG9mIHZhcmlhYmxlcyBmb3IgZWFjaCB5ZWFyLCB3ZSBjYW4gY29lcmNlIHRoZSBkYXRhIHRvIGJlIGNvbWJpbmVkIGludG8gb25lIHRpYmJsZSBieSB1c2luZyB0aGUgYGJpbmRfcm93cygpYCBmdW5jdGlvbiBvZiBgZHBseXJgLiBJbXBvcnRhbnRseSwgdGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXF1aXJlIHRoYXQgdGhlIGNvbHVtbnMgYmUgdGhlIHNhbWUuICBUaGlzIHdpbGwgY3JlYXRlIE5BIHZhbHVlcyBmb3IgYW55IHZhcmlhYmxlIHRoYXQgaXMgbm90IHByZXNlbnQgaW4gZ2l2ZW4gZGF0YSBmcmFtZSBidXQgaXMgIHByZXNlbnQgaW4gb25lIG9mIHRoZSBvdGhlciBkYXRhIGZyYW1lcyB0aGF0IGlzIGJlaW5nIGNvbWJpbmVkLiBOb3RlIHRoYXQgdGhlIGBiaW5kX2NvbHMoKWAgZnVuY3Rpb24gZG9lcyBleHBlY3QgdGhhdCB0aGUgcm93cyBtYXRjaC4gVGhlIGAuaWRgIGFyZ3VtZW50IHdpbGwgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHdpdGggdmFsdWVzIHRvIGxpbmsgZWFjaCByb3cgdG8gaXRzIG9yaWdpbmFsIGRhdGEgZnJhbWUuIEZvciBtb3JlIGluZm9ybWF0aW9uIHNlZSBbaGVyZV0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9iaW5kLmh0bWwpLgoKCmBgYHtyfQpueXRzX2RhdGEgPC0gbnl0c19kYXRhICU+JQogIG1hcF9kZihiaW5kX3Jvd3MsIC5pZCA9ICJ5ZWFyIikKCmdsaW1wc2Uobnl0c19kYXRhKQpgYGAKCldlIHdpbGwgd2FudCB0byBkbyBzb21lIG9mIG91ciBhbmFseXNpcyBzcGxpdCBieSB5ZWFyLCBzbyB3ZSB3b3VsZCBsaWtlIHRvIGJlIHN1cmUgd2UgaGF2ZSBvbmUgdmFyaWFibGUgdGhhdCBoYXMgdGhlIGNvcnJlY3QgdmFsdWUgZm9yIHllYXIuIEl0IGxvb2tzIGxpa2Ugd2UganVzdCBuZWVkIHRvIHJlbW92ZSBgIm55dHMiYCBmcm9tIHRoZSB5ZWFyIHZhcmlhYmxlIHRoYXQgd2UgY3JlYXRlZCBmcm9tIHRoZSBuYW1lcyBvZiB0aGUgdGliYmxlcyBpbiBvdXIgbGlzdCBhbmQgd2Ugc2hvdWxkIGJlIGFsbCBzZXQuIFdlIHdpbGwgdXNlIGFub3RoZXIgZnVuY3Rpb24gZnJvbSB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gZG8gdGhpcy4gVGhlIGBzdHJfcmVtb3ZlKClgIGZ1bmN0aW9uIHRha2VzIGEgc3RyaW5nIGZvbGxvd2VkIGJ5IGEgcGF0dGVybiBhbmQgcmVtb3ZlcyB0aGUgcGF0dGVybiBmcm9tIHRoZSBzdHJpbmcuCgpgYGB7cn0Kbnl0c19kYXRhIDwtIG55dHNfZGF0YSAlPiUKICBtdXRhdGUoeWVhciA9IGFzLm51bWVyaWMoc3RyX3JlbW92ZSh5ZWFyLCAibnl0cyIpKSkKYGBgCgpIZXJlIGlzIG91ciBjbGVhbiBhbmQgd3JhbmdsZWQgZGF0YToKCiMjIyMgey5zY3JvbGxhYmxlfQpgYGB7cn0KZ2xpbXBzZShueXRzX2RhdGEpCgpgYGAKCiMjIyMKCgpOb3RlIHRoYXQgdGhlcmUgYXJlIHNldmVyYWwgdmFyaWFibGVzIHdoZXJlIHRoZXJlIGFyZSBzaW1pbGFyIG5hbWVzLCBidXQgd2l0aCBhIGBDYCBjb21wYXJlZCB0byBhbiBgRWAgaW4gdGhlIHZhcmlhYmxlIG5hbWUuIFRob3NlIHN0YXJ0aW5nIHdpdGggYENgIGFyZSByZWxhdGVkIHRvIHF1ZXN0aW9ucyBhYm91dCBjdXJyZW50IHVzYWdlIChsYXN0IDMwIGRheXMpLCB3aGlsZSB0aG9zZSB3aXRoIGFuIGBFYCBhcmUgcmVsYXRlZCB0byB1c2FnZSBhY3Jvc3MgdGhlIHN0dWRlbnQgcmVzcG9uZGVudCdzIHdob2xlIGxpZmUgKCJldmVyIiB1c2FnZSkuIFdlIHdpbGwgZGlzY3VzcyB0aGVzZSBncm91cHMgZnVydGhlciBiZWxvdy4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIGV2YWwgPSBGQUxTRX0Kc2F2ZShueXRzX2RhdGEsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKIyMjICoqVmFyaWFibGUgVGFibGUqKgoqKioKPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGEgdGFibGUgYWJvdXQgdGhlIGZpbmFsIHZhcmlhYmxlcyBpbiBvdXIgZGF0YSBzZXQuIDwvc3VtbWFyeT4KCnZhbHVlIDEgPSB5ZXMsIHZhbHVlIDIgPSBubwoKVmFyaWFibGUgICB8IERldGFpbHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoqKnllYXIqKiAgfCB0aGUgeWVhciB0aGF0IHRoZSBzdXJ2ZXkgcmVzdWx0cyBmcm9tIGEgcGFydGljdWxhciBzdHVkZW50IHJlc3BvbmRlbnQgd2VyZSBhY3F1aXJlZCAgCioqcHN1KiogfCB0aGUgcHJpbWFyeSBzYW1wbGluZyB1bml0IGZvciB0aGUgc3VydmV5IHdlaWdodGluZyAgCioqZmlud2d0KiogfCB0aGUgZmluYWwgYW5hbHlzaXMgd2VpZ2h0IGZvciB0aGUgc3VydmV5IHdlaWdodGluZyAgCioqc3RyYXR1bSoqIHwgdGhlIHN0cmF0dW0gdXNlZCBmb3IgdmFyaWFuY2UgZXN0aW1hdGlvbiBmb3IgdGhlIHN1cnZleSB3ZWlnaHRpbmcgIAoqKkFnZSoqIHwgdGhlIGFnZSBvZiB0aGUgc3R1ZGVudCB3aGVuIHRoZXkgdG9vayB0aGUgc3VydmV5ICAKKipTZXgqKiB8IHRoZSBzZXggb2YgdGhlIHN0dWRlbnQgd2hlbiB0aGV5IHRvb2sgdGhlIHN1cnZleSAgCioqR3JhZGUqKiB8IHRoZSBncmFkZSBvZiB0aGUgdGhlIHN0dWRlbnQgd2hlbiB0aGUgdG9vayB0aGUgc3VydmV5ICAKKipFQ0lHVCoqIHwgc3R1ZGVudCByZXBvcnRlZCBoYXZpbmcgZXZlciB0cmllZCBjaWdhcmV0dGUgc21va2luZywgZXZlbiBvbmUgb3IgdHdvIHB1ZmZzICAKKipFQ0lHQVIqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgY2lnYXIsIGNpZ2FyaWxsbywgb3IgbGl0dGxlIGNpZ2FyIHNtb2tpbmcsIGV2ZW4gb25lIG9yIHR3byBwdWZmcyAgCioqRVNMVCoqIHwgc3R1ZGVudCByZXBvcnRlZCBoYXZpbmcgZXZlciB0cmllZCBjaGV3aW5nIHRvYmFjY28sIHNudWZmLCBvciBkaXAgIAoqKkVFTENJR1QqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgZS1jaWdhcmV0dGVzICAKKipFUk9MTENJR1RTKiogfCBzdHVkZW50IHJlcG9ydGVkIGhhdmluZyBldmVyIHRyaWVkIHJvbGwteW91ci1vd24gY2lnYXJldHRlcyAgCioqRUZMQVZDSUdUUyoqIHwgICgyMDE1IG9ubHkpIGJhc2VkIG9uIGFuc3dlciB0byAiV2hpY2ggb2YgdGhlIGZvbGxvd2luZyB0b2JhY2NvIHByb2R1Y3RzIHRoYXQgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cyB3ZXJlIGZsYXZvcmVkPyIgIAoqKkVCSURJUyoqIHwgc3R1ZGVudCByZXBvcnRlZCBoYXZpbmcgZXZlciB0cmllZCBiaWRpcyAoc21hbGwgYnJvd24gY2lnYXJldHRlcyB3cmFwcGVkIGluIGEgbGVhZikgIAoqKkVGTEFWQ0lHQVIqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgYSBmbGF2b3JlZCBjaWdhciAoMjAxNS0yMDE2KQoqKkVIT09LQUgqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgc21va2VkIHRvYmFjY28gZnJvbSBhIGhvb2thaCBvciBhIHdhdGVycGlwZSAgCioqRVBJUEUqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgc21va2VkIHRvYmFjY28gZnJvbSBhIHBpcGUgKG5vdCBob29rYWgpICAKKipFU05VUyoqIHwgc3R1ZGVudCByZXBvcnRlZCBoYXZpbmcgZXZlciB1c2VkIHNudXMsIHN1Y2ggYXMgQ2FtZWwgb3IgTWFsYm9ybyBTbnVzICAKKipFRElTU09MVioqIHwgc3R1ZGVudCByZXBvcnRlZCBoYXZpbmcgZXZlciB0cmllZCBkaXNzb2x2YWJsZSB0b2JhY2NvIHByb2R1Y3RzIHN1Y2ggYXMgQXJpdmEsIFN0b25ld2FsbCwgQ2FtZWwgb3JicywgQ2FtZWwgc3RpY2tzLCBNYXJsYm9ybyBzdGlja3MsIG9yIENhbWVsIHN0cmlwcyAgCioqQ0NJR1QqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSBzbW9rZWQgY2lnYXJldHRlcyBvbiA+PSAxIG9mIHRoZSBwYXN0IDMwIGRheXMgIAoqKkNDSUdBUioqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHNtb2tlZCBjaWdhcnMgb24gPj0gMSBvZiB0aGUgcGFzdCAzMCBkYXlzICAKKipDU0xUKiogfCBzdHVkZW50IHJlcG9ydGVkIHRoZXkgdXNlZCBjaGV3aW5nIHRvYmFjY28sIHNudWZmLCBvciBkaXAgb24gPj0gMSBvZiB0aGUgcGFzdCAzMCBkYXlzICAKKipDRUxDSUdUKiogfCBzdHVkZW50IHJlcG9ydGVkIHRoZXkgdXNlZCBlbGVjdHJvbmljIGNpZ2FyZXR0ZXMgb3IgZS1jaWdhcmV0dGVzIG9uZSBvciBtb3JlIGRheXMgaW4gdGhlIHBhc3QgMzAKKipDUk9MTENJR1RTKiogfCBzdHVkZW50IHJlcG9ydGVkIHRoZXkgc21va2VkIHJvbGwteW91ci1vd24gY2lnYXJldHRlcyBkdXJpbmcgdGhlIHBhc3QgMzAgZGF5cyAgCioqQ0ZMQVZDSUdUUyoqfCAoMjAxNSBvbmx5KSBiYXNlZCBvbiBhbnN3ZXIgdG8gIldoaWNoIG9mIHRoZSBmb2xsb3dpbmcgdG9iYWNjbyBwcm9kdWN0cyB0aGF0IHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXMgd2VyZSBmbGF2b3JlZD8iIAoqKkNCSURJUyoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHNtb2tlZCBiaWRpcyBkdXJpbmcgdGhlIHBhc3QgMzAgZGF5cyAgCioqQ0hPT0tBSCoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHNtb2tlZCB0b2JhY2NvIGluIGEgaG9va2FoIG9uID49IDEgb2YgdGhlIHBhc3QgMzAgZGF5cyAgCioqQ1BJUEUqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgdGhleSBzbW9rZWQgdG9iYWNjbyBpbiBhIHBpcGUgKG5vdCBob29rYWgpIGR1cmluZyB0aGUgcGFzdCAzMCBkYXlzICAKKipDU05VUyoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHVzZWQgc251cyBkdXJpbmcgdGhlIHBhc3QgMzAgZGF5cyAgICAKKipDRElTU09MVioqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHVzZWQgZGlzc29sdmFibGUgdG9iYWNjbyBwcm9kdWN0cyBzdWNoIGFzIEFyaXZhLCBTdG9uZXdhbGwsIENhbWVsIG9yYnMsIENhbWVsIHN0aWNrcywgTWFybGJvcm8gc3RpY2tzLCBvciBDYW1lbCBzdHJpcHMgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMgIAoqKmJyYW5kX2VjaWcqKiB8IHN0dWRlbnQgYW5zd2VyIHRvICJEdXJpbmcgdGhlIHBhc3QgMzAgZGF5cywgd2hhdCBicmFuZCBvZiBlLWNpZ2FyZXR0ZXMgZGlkIHlvdSB1c3VhbGx5IHVzZT8iICAKKiptZW50aG9sKiogfCBzdHVkZW50IHNlbGVjdGVkIE1lbnRob2wgb3IgbWludCBhcyB0aGUgYW5zd2VyIHRvICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChzZWxlY3Qgb25lIG9yIG1vcmUpIiAgCioqY2xvdmVfc3BpY2UqKiB8IHN0dWRlbnQgc2VsZWN0ZWQgY2xvdmUgb3Igc3BpY2UgYXMgdGhlIGFuc3dlciB0byAiV2hhdCBmbGF2b3JzIG9mIHRvYmFjY28gcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBpbiB0aGUgcGFzdCAzMCBkYXlzPyAoc2VsZWN0IG9uZSBvciBtb3JlKSIgIAoqKmZydWl0KiogfCBzdHVkZW50IHNlbGVjdGVkIGZydWl0IGFzIHRoZSBhbnN3ZXIgdG8gIldoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKHNlbGVjdCBvbmUgb3IgbW9yZSkiICAKKipjaG9jb2xhdGUqKiB8IHN0dWRlbnQgc2VsZWN0ZWQgY2hvY29sYXRlIGFzIHRoZSBhbnN3ZXIgdG8gIldoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKHNlbGVjdCBvbmUgb3IgbW9yZSkiICAKKiphbGNvaG9saWNfZHJpbmsqKiB8IHN0dWRlbnQgc2VsZWN0ZWQgYWxjb2hvbGljIGRyaW5rIChzdWNoIGFzIHdpbmUsIGNvZ25hYywgbWFyZ2FyaXRhLCBvciBvdGhlciBjb2NrdGFpbHMpIGFzIHRoZSBhbnN3ZXIgdG8gIldoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKGNob29zZSBvbmUgb3IgbW9yZSkiICAKKipjYW5keV9kZXNzZXJ0X3N3ZWV0cyoqIHwgIHN0dWRlbnQgc2VsZWN0ZWQgY2FuZHksIGRlc3NlcnRzIG9yIG90aGVyIHN3ZWV0cyBhcyB0aGUgYW5zd2VyIHRvICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0IDMwIGRheXM/IChjaG9vc2Ugb25lIG9yIG1vcmUpIiAKKipvdGhlcioqIHwgc3R1ZGVudCBzZWxlY3RlZCBzb21lIG90aGVyIGZsYXZvciBub3QgbGlzdGVkIGFzIHRoZSBhbnN3ZXIgdG8gIldoYXQgZmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIGhhdmUgeW91IHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cz8gKGNob29zZSBvbmUgb3IgbW9yZSkiIAoqKkVIVFAqKiB8IHN0dWRlbnQgcmVwb3J0ZWQgaGF2aW5nIGV2ZXIgdHJpZWQgaGVhdGVkIChhbHNvIGtub3duIGFzICJoZWF0LW5vdC1idXJuIikgdG9iYWNjbyBwcm9kdWN0cyAgCioqQ0hUUCoqIHwgc3R1ZGVudCByZXBvcnRlZCB0aGV5IHVzZWQgaGVhdGVkIHRvYmFjY28gcHJvZHVjdHMgZHVyaW5nIHRoZSBwYXN0IDMwIGRheXMgIAo8L2RldGFpbHM+CgojIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqCioqKiAKClJlY2FsbCB0aGF0IG91ciBtYWluIHF1ZXN0aW9ucyB3ZXJlOgoKMSkgSG93IGhhcyB0b2JhY2NvIGFuZCBlLWNpZ2FyZXR0ZS92YXBpbmcgdXNlIGJ5IEFtZXJpY2FuIHlvdXRocyBjaGFuZ2VkIHNpbmNlIDIwMTU/CjIpIEhvdyBkb2VzIGUtY2lnYXJldHRlIHVzZSBjb21wYXJlIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXM/CjMpIFdoYXQgdmFwaW5nIGJyYW5kcyBhbmQgZmxhdm9ycyBhcHBlYXIgdG8gYmUgdXNlZCB0aGUgbW9zdCBmcmVxdWVudGx5PyAgCldlIHdpbGwgYmFzZSB0aGlzIG9uIHRoZSBmb2xsb3dpbmcgc3VydmV5IHF1ZXN0aW9uczogICAKPiAiRHVyaW5nIHRoZSBwYXN0IDMwIGRheXMsIHdoYXQgYnJhbmQgb2YgZS1jaWdhcmV0dGVzIGRpZCB5b3UgdXN1YWxseSB1c2U/IiAgIAo+IiBXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0CjMwIGRheXM/IiAKCjQpIElzIHRoZXJlIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gZS1jaWdhcmV0dGUvdmFwaW5nIHVzZSBhbmQgb3RoZXIgdG9iYWNjbyB1c2U/CgoKV2UgYXJlIG5vdyBnb2luZyB0byBjcmVhdGUgZGF0YSB2aXN1YWxpemF0aW9ucyB0byBleHBsb3JlIGVhY2ggb2YgdGhlc2UgcXVlc3Rpb25zLgoKRm9yIG1hbnkgb2YgdGhlc2UgcXVlc3Rpb25zIHdlIHdpbGwgYmUgaW50ZXJlc3RlZCBpbiBib3RoICoqY3VycmVudCoqIGFuZCAqKmV2ZXIqKiB1c2Vycywgc28gd2Ugd2lsbCB3YW50IHRvIGNyZWF0ZSBhIHZhcmlhYmxlIGZvciBsYWJlbGluZyBpbmRpdmlkdWFscyB3aG8gYXJlIGN1cnJlbnQgdXNlcnMgb2YgYW55IHRvYmFjY28gcHJvZHVjdCAob3Igbm90LCBpLmUuLCB3aG8gZG8gbm90IGN1cnJlbnRseSB1c2UgYSB0b2JhY2NvIHByb2R1Y3QpIGFuZCBhIHZhcmlhYmxlIGZvciBsYWJlbGluZyBpbmRpdmlkdWFscyB3aG8gYXJlICJldmVyIHVzZXJzIiBvZiBhbnkgdG9iYWNjbyBwcm9kdWN0IChvciBub3QsIGkuZS4sIHdobyBoYXZlIG5ldmVyIHVzZWQgYSB0b2JhY2NvIHByb2R1Y3QpLgoKV2UgZGVmaW5lIHRoZXNlIHR3byBncm91cHMgYXMgZm9sbG93czoKCjEpICoqY3VycmVudCoqID0gc3R1ZGVudHMgd2hvIHVzZWQgYSBwcm9kdWN0IGZvciA+PTEgZGF5IGluIHRoZSBwYXN0IDMwIGRheXMgIAoyKSAqKmV2ZXIqKiA9ICBzdHVkZW50cyB3aG8gcmVwb3J0IGhhdmluZyB1c2VkIG9yIHRyaWVkIGEgcHJvZHVjdCBhdCBhbnkgcG9pbnQgaW4gdGltZQoKQWxsICoqY3VycmVudCoqIHVzZXJzIGFyZSB0aGVyZWZvcmUgKipldmVyKiogdXNlcnMgYnV0IG5vdCBhbGwgKipldmVyKiogdXNlcnMgYXJlICoqY3VycmVudCoqIHVzZXJzLiBUaHVzLCAqKmN1cnJlbnQqKiB1c2VycyBhcmUgYSBzdWJzZXQgb2YgKipldmVyKiogdXNlcnMuCgpUbyBhZGQgdGhlc2UgZ3JvdXBpbmcgdmFyaWFibGVzIHRvIG91ciBkYXRhIHdlIHdpbGwgZG8gYSBiaXQgbW9yZSB3cmFuZ2xpbmcgdXNpbmcgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gYWdhaW4gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gQXMgZGlzY3Vzc2VkIGFib3ZlLCBvdXIgZGF0YSBzZXQgY29udGFpbnMgYSBzZXQgb2YgcXVlc3Rpb25zIHRoYXQgcmVsYXRlIHRvIHdoZXRoZXIgdGhlIHN0dWRlbnQgaGFzIGV2ZXIgdXNlZCB0aGUgcGFydGljdWxhciB0b2JhY2NvIHByb2R1Y3QgKHF1ZXN0aW9ucyB0aGF0IHN0YXJ0IHdpdGggdGhlIGxldHRlciAiRSIpLCBhbmQgcXVlc3Rpb25zIHRoYXQgcmVsYXRlIHRvIHdoZXRoZXIgdGhlIHN0dWRlbnQgY3VycmVudGx5IHVzZXMgdGhlIHBhcnRpY3VsYXIgdG9iYWNjbyBwcm9kdWN0IChxdWVzdGlvbnMgdGhhdCBzdGFydCB3aXRoIHRoZSBsZXR0ZXIgIkMiKS4gCgpIZXJlIGFyZSBzb21lIGV4YW1wbGVzIGZvciB0aGVzZSBkYXRhIGVudHJpZXM6ICAKCiAtIEVQSVBFOiBTdHVkZW50cyB3aG8gcmVwb3J0ZWQgdGhleSBoYXZlIHNtb2tlZCB0b2JhY2NvIGZyb20gYSBwaXBlIChub3QgaG9va2FoKS4gIAogLSBDUElQRTogU3R1ZGVudHMgd2hvIHJlcG9ydGVkIHRoZXkgc21va2VkIHRvYmFjY28gaW4gYSBwaXBlIChub3QgaG9va2FoKSBkdXJpbmcgdGhlIHBhc3QgMzAgZGF5cy4gCiAtIEVST0xMQ0lHVFM6IFJFQ09ERTogU3R1ZGVudHMgd2hvIHJlcG9ydGVkIHRoZXkgaGF2ZSB0cmllZCBzbW9raW5nIHJvbGwteW91ci1vd24gY2lnYXJldHRlcy4gCiAtIENST0xMQ0lHVFM6IFJFQ09ERTogU3R1ZGVudHMgd2hvIHJlcG9ydGVkIHRoZXkgc21va2VkIHJvbGwteW91ci1vd24gY2lnYXJldHRlcyBkdXJpbmcgdGhlIHBhc3QgMzAgZGF5cy4gCiAKQmFzZWQgb24gbWFueSBxdWVzdGlvbnMgbGlrZSB0aGlzOiAgCiAKIEluIHRoZSBwYXN0IDMwIGRheXMsIHdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgcHJvZHVjdHMgaGF2ZSB5b3UgdXNlZCBvbiBhdCBsZWFzdCBvbmUgZGF5PyAoU2VsZWN0IG9uZSBvciBtb3JlKSAKQS4gUm9sbC15b3VyLW93biBjaWdhcmV0dGVzICAKQi4gUGlwZXMgZmlsbGVkIHdpdGggdG9iYWNjbyAobm90IGhvb2thaCBvciB3YXRlcnBpcGUpICAKQy4gU251cywgc3VjaCBhcyBDYW1lbCwgTWFybGJvcm8sIG9yIEdlbmVyYWwgU251cyAgCkQuIERpc3NvbHZhYmxlIHRvYmFjY28gcHJvZHVjdHMgc3VjaCBhcyBBcml2YSwgU3RvbmV3YWxsLCBDYW1lbCBvcmJzLCBDYW1lbCBzdGlja3MsIE1hcmxib3JvIHN0aWNrcywKb3IgQ2FtZWwgc3RyaXBzICAKRS4gQmlkaXMgKHNtYWxsIGJyb3duIGNpZ2FyZXR0ZXMgd3JhcHBlZCBpbiBhIGxlYWYpICAKRi4gSSBoYXZlIG5vdCB1c2VkIGFueSBvZiB0aGUgcHJvZHVjdHMgbGlzdGVkIGFib3ZlIGluIHRoZSBwYXN0IDMwIGRheXMgIAoKIFdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSBldmVyIHRyaWVkLCBldmVuIGp1c3Qgb25lIHRpbWU/IChTZWxlY3Qgb25lIG9yIG1vcmUpICAKQS4gUm9sbC15b3VyLW93biBjaWdhcmV0dGVzICAKQi4gUGlwZXMgZmlsbGVkIHdpdGggdG9iYWNjbyAobm90IGhvb2thaCBvciB3YXRlcnBpcGUpICAKQy4gU251cywgc3VjaCBhcyBDYW1lbCwgTWFybGJvcm8sIG9yIEdlbmVyYWwgU251cyAgCkQuIERpc3NvbHZhYmxlIHRvYmFjY28gcHJvZHVjdHMgc3VjaCBhcyBBcml2YSwgU3RvbmV3YWxsLCBDYW1lbCBvcmJzLCBDYW1lbCBzdGlja3MsIE1hcmxib3JvIHN0aWNrcywgb3IgQ2FtZWwgc3RyaXBzICAKRS4gQmlkaXMgKHNtYWxsIGJyb3duIGNpZ2FyZXR0ZXMgd3JhcHBlZCBpbiBhIGxlYWYpICAKRi4gSSBoYXZlIG5ldmVyIHRyaWVkIGFueSBvZiB0aGUgcHJvZHVjdHMgbGlzdGVkIGFib3ZlICAgCiAKIApXZSB3aWxsIHN1bSBhY3Jvc3MgdGhlIHZhcmlhYmxlcyB0aGF0IHJlbGF0ZSB0byBldmVyIG9yIGN1cnJlbnQgdG9iYWNjbyB1c2FnZSBxdWVzdGlvbnMgdG8gZGV0ZXJtaW5lIGlmIHRoZSBzdHVkZW50IGFuc3dlcmVkIHllcyB0byBhbnkgb2YgdGhlIGV2ZXIgb3IgY3VycmVudCBxdWVzdGlvbnMuIFRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGJhc2UgYHJvd1N1bXNgIGZ1bmN0aW9uLgoKV2Ugd2lsbCB0aGVuIHVzZSB0aGUgYGNhc2Vfd2hlbigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGNvbnZlcnQgdGhlIHN1bSB2YWx1ZXMgdG8gYFRSVUVgIG9yIGBGQUxTRWAgYmFzZWQgb24gdGhlIHRocmVzaG9sZCBvZiB6ZXJvLiBJZiB0aGUgc3VtIGlzIGdyZWF0ZXIgdGhhbiB6ZXJvLCB0aGVuIHdlIGtub3cgdGhlIHN0dWRlbnQgYW5zd2VyZWQgeWVzIHRvIGF0IGxlYXN0IG9uZSBxdWVzdGlvbi4gCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojaW4gY2FzZSB5b3UgYXJlIHN0YXJ0aW5nIGF0IHRoaXMgc2VjdGlvbi0gbmVlZCB0byBsb2FkIHRoZSBkYXRhOgpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgpgYGB7cn0Kbnl0c19kYXRhICU8PiUKICBtdXRhdGUodG9iYWNjb19zdW1fZXZlciA9IHJvd1N1bXMoc2VsZWN0KC4sIHN0YXJ0c193aXRoKCJFIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpKSwgbmEucm0gPSBUUlVFKSwKICAgICAgdG9iYWNjb19zdW1fY3VycmVudCA9IHJvd1N1bXMoc2VsZWN0KC4sIHN0YXJ0c193aXRoKCJDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gRkFMU0UpKSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICAgIG11dGF0ZSh0b2JhY2NvX2V2ZXIgPSBjYXNlX3doZW4odG9iYWNjb19zdW1fZXZlciA+IDAgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvYmFjY29fc3VtX2V2ZXIgPT0gMCB+IEZBTFNFKSwKICAgICAgICAgIHRvYmFjY29fY3VycmVudCA9IGNhc2Vfd2hlbih0b2JhY2NvX3N1bV9jdXJyZW50ID4gMCB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9iYWNjb19zdW1fY3VycmVudCA9PSAwIH4gRkFMU0UpKQpgYGAKIAogCiMjIyMgey5zY3JvbGxhYmxlfQpgYGB7cn0KZ2xpbXBzZShueXRzX2RhdGEpCmBgYAojIyMjCgpXZSBhcmUgYWxzbyBpbnRlcmVzdGVkIGluIGUtY2lnYXJldHRlL3ZhcGluZyBwcm9kdWN0IHVzYWdlIGNvbXBhcmVkIHRvIG90aGVyIHRvYmFjY28gcHJvZHVjdHMsIHNvIHdlIHdpbGwgY3JlYXRlIHNvbWUgdmFyaWFibGVzIHJlbGF0ZWQgdG8gdGhlIHN1bSBvZiBhbGwgZS1jaWdhcmV0dGUgdXNhZ2UgcXVlc3Rpb24gdmFyaWFibGVzIGFuZCB0aGUgc3VtIG9mIGFsbCB0b2JhY2NvIHVzYWdlIHF1ZXN0aW9uIHZhcmlhYmxlcyBleGNsdWRpbmcgdGhvc2UgdGhhdCBhcmUgYWJvdXQgZS1jaWdhcmV0dGVzLiBUaGVyZSBpcyBvbmx5IG9uZSB2YXJpYWJsZSBhYm91dCBlLWNpZ2FyZXR0ZSB1c2FnZSBldmVyIChFRUxDSUdUKSBhbmQgb25lIGFib3V0IGN1cnJlbnQgdXNhZ2UgKENFTENJR1QpLgoKCmBgYHtyfQpueXRzX2RhdGEgPC0gbnl0c19kYXRhICU+JSAKICBtdXRhdGUoZWNpZ19zdW1fZXZlciA9IHJvd1N1bXMoc2VsZWN0KC4sIEVFTENJR1QpLCBuYS5ybSA9IFRSVUUpLAogICAgICBlY2lnX3N1bV9jdXJyZW50ID0gcm93U3VtcyhzZWxlY3QoLiwgQ0VMQ0lHVCksIG5hLnJtID0gVFJVRSksCiAgICAgbm9uX2VjaWdfc3VtX2V2ZXIgPSByb3dTdW1zKHNlbGVjdCguLCBzdGFydHNfd2l0aCgiRSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUVFTENJR1QpLCBuYS5ybSA9IFRSVUUpLAogIG5vbl9lY2lnX3N1bV9jdXJyZW50ID0gcm93U3VtcyhzZWxlY3QoLiwgc3RhcnRzX3dpdGgoIkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBGQUxTRSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUNFTENJR1QpLCBuYS5ybSA9IFRSVUUpKSAlPiUKICAgICAgbXV0YXRlKGVjaWdfZXZlciA9IGNhc2Vfd2hlbihlY2lnX3N1bV9ldmVyID4gMCB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19zdW1fZXZlciA9PSAwIH4gRkFMU0UpLAogICAgICAgICAgZWNpZ19jdXJyZW50ID0gY2FzZV93aGVuKGVjaWdfc3VtX2N1cnJlbnQgPiAwIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX3N1bV9jdXJyZW50ID09IDAgfiBGQUxTRSksCiAgICAgICAgIG5vbl9lY2lnX2V2ZXIgPSBjYXNlX3doZW4obm9uX2VjaWdfc3VtX2V2ZXIgPiAwIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19zdW1fZXZlciA9PSAwIH4gRkFMU0UpLAogICAgICBub25fZWNpZ19jdXJyZW50ID0gY2FzZV93aGVuKG5vbl9lY2lnX3N1bV9jdXJyZW50ID4gMCB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfc3VtX2N1cnJlbnQgPT0gMCB+IEZBTFNFKSkKYGBgICAgICAgICAgICAgICAgICAgICAgICAKCiMjIyMgey5zY3JvbGxhYmxlfQpgYGB7cn0KZ2xpbXBzZShueXRzX2RhdGEpCmBgYAoKIyMjIwoKRmluYWxseSwgd2UgYXJlIGFsc28gaW50ZXJlc3RlZCBpbiBncm91cGluZyBzdHVkZW50cyB0aGF0IG9ubHkgdXNlIGUtY2lnYXJldHRlcyBhbmQgdGhvc2UgdGhhdCBvbmx5IHVzZSBvdGhlciBmb3JtcyBvZiB0b2JhY2NvLgoKUmVjYWxsIHRoYXQgY3VycmVudCB1c2VycyBhcmUgYSBzdWJzZXQgb2YgZXZlciB1c2VycywgdGh1cyBzdHVkZW50cyB3b3VsZCB0eXBpY2FsbHkgYW5zd2VyIHllcyB0byBoYXZpbmcgdHJpZWQgdmFwaW5nIHByb2R1Y3RzIGlmIHRoZXkgaGFkIHVzZWQgdGhlbSBvbmUgb3IgbW9yZSBkYXlzIGluIHRoZSBwYXN0IDMwIGRheXMuCgpGaXJzdCB3ZSB3aWxsIG1ha2UgYSBzbWFsbCB0b3kgZGF0YXNldCBjYWxsZWQgYHRlc3RgIHRvIHNob3cgd2hhdCB3ZSB3aWxsIGRvIHdpdGggdGhlIGxhcmdlciBkYXRhc2V0OgpgYGB7cn0KdGVzdCA8LSB0aWJibGUoZWNpZ19ldmVyID0gYygiVFJVRSIsICJUUlVFIiwgIlRSVUUiLCAiVFJVRSIsICJGQUxTRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZBTFNFIiwgIlRSVUUiLCAiRkFMU0UiLCAiRkFMU0UiKSwKICAgICAgICAgICAgICAgbm9uX2VjaWdfZXZlciA9IGMoIlRSVUUiLCAiRkFMU0UiLCAiRkFMU0UiLCAiRkFMU0UiLCAiRkFMU0UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRkFMU0UiLCAiVFJVRSIsICJUUlVFIiwgIlRSVUUiKSwKICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID0gYygiVFJVRSIsICJGQUxTRSIsICJGQUxTRSIsICJUUlVFIiwgIlRSVUUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRkFMU0UiLCAiRkFMU0UiLCAiRkFMU0UiLCAiRkFMU0UiKSwKICAgICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudCA9IGMoIlRSVUUiLCAiRkFMU0UiLCAiVFJVRSIsICJGQUxTRSIsICJUUlVFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZBTFNFIiwgIkZBTFNFIiwgIkZBTFNFIiwgIlRSVUUiKSkKCnRlc3QKYGBgCgpOb3csIGxldCdzIGxvb2sgYXQgaWRlbnRpZnlpbmcgc3R1ZGVudHMgd2hvIGhhdmUgdHJpZWQgZS1jaWdhcmV0dGVzLCBidXQgYXJlIG5vdCBjdXJyZW50IHVzZXJzLCBhbmQgd2hvIGhhdmUgbmV2ZXIgdHJpZWQgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyAoYW5kIGFyZSB0aGVyZWZvcmUgbm90IGN1cnJlbnQgdXNlcnMpLiBXZSB3aWxsIGFnYWluIHVzZSB0aGUgYGNhc2Vfd2hlbigpYCBhbmQgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBuZXcgdmFyaWFibGVzIHdpdGggc3BlY2lmaWMgdmFsdWVzIHdoZW4gY2VydGFpbiBjb25kaXRpb25zIGFyZSBtZXQuIEluIHRoaXMgY2FzZSwgd2Ugd2lsbCBzcGVjaWZ5IHRoYXQgc2V2ZXJhbCBjb25kaXRpb25zIG11c3QgYmUgbWV0IGJ5IHVzaW5nIHRoZSBgJmAgc3ltYm9sLiBGb3IgYSB2YWx1ZSBvZiBgVFJVRWAgZm9yIHRoZSBuZXcgYGVjaWdfb25seV9ldmVyYCB2YXJpYWJsZSwgYWxsIG9mIHRoZSBjb25kaXRpb25zIGNvbWJpbmVkIHdpdGggYCZgIG11c3QgYmUgbWV0LiAgSWYgYW55IG9mIHRoZSBjb25kaXRpb25zIGFyZSBub3QgbWV0IHRoZW4gdGhlIGBlY2lnX29ubHlfZXZlcmAgdmFsdWUgd2lsbCBiZSBgRkFMU0VgIGJhc2VkIG9uIHRoZSBsYXN0IGxpbmUgYFRSVUUgfiBGQUxTRWAuCgpgYGB7cn0KCnRlc3QgPC0gdGVzdCAlPiUgbXV0YXRlKGVjaWdfb25seV9ldmVyID0gY2FzZV93aGVuKGVjaWdfZXZlciA9PSBUUlVFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSkKdGVzdApgYGAKCldlIGNhbiBzZWUgZnJvbSB0aGUgc2Vjb25kIHJvdywgdGhhdCB0aGUgYGVjaWdfb25seV9ldmVyYCBpcyBgVFJVRWAgd2hlbiB3ZSB3b3VsZCBleHBlY3QgaXQgdG8gYmUuCldlIGNhbiBhbHNvIHNlZSBmcm9tIHRoZSBmb3VydGggcm93LCB0aGF0IGV2ZW4gdGhvdWdoIHRoZSBzdHVkZW50IHJlcG9ydGVkIHllcyB0byBldmVyIHRyeWluZyBlLWNpZ2FyZXR0ZXMsIGJlY2F1c2UgdGhleSBhbHNvIHJlcG9ydGVkIHllcyB0byBjdXJyZW50bHkgdXNpbmcgZS1jaWdhcmV0dGVzIHRoZSB2YWx1ZSBmb3Igb25seSBldmVyIHRyeWluZyBlLWNpZ2FyZXR0ZXMgaXMgYEZBTFNFYC4gQWRkaXRpb25hbGx5IHdlIGNhbiBzZWUgZnJvbSB0aGUgc2V2ZW50aCByb3cgdGhhdCBzaW1pbGFybHkgZXZlbiB0aG91Z2ggdGhlIHN0dWRlbnQgcmVwb3J0ZWQgeWVzdCB0byBldmVyIHRyeWluZyBlLWNpZ2FyZXR0ZXMsIHRoZXkgYWxzbyByZXBvcnRlZCB5ZXMgdG8gZXZlciB0cnlpbmcgb3RoZXIgcHJvZHVjdHMsIGFuZCB0aGUgdmFsdWUgZm9yIG9ubHkgZXZlciB0cnlpbmcgZS1jaWdhcmV0dGVzIGlzIGBGQUxTRWAuIEltcG9ydGFudGx5LCB3ZSBjYW4gc2VlIGZyb20gdGhlIDZ0aCByb3csIHRoYXQgaWYgYWxsIHJlc3BvbnNlcyBhcmUgbmVnYXRpdmUgdGhhbiB0aGUgdmFsdWUgaXMgYEZBTFNFYC4KCk5vdyB3ZSB3aWxsIGV4cGFuZCB0aGlzIHRvIHRoZSBvdGhlciBwb3NzaWJsZSBjYXRlZ29yaWVzLiBJbiB0aGlzIGNhc2Ugd2Ugbm90ZSB0aGF0IHNpbmNlIGN1cnJlbnQgdXNlcnMgYXJlIGEgc3Vic2V0IG9mIGV2ZXIgdXNlcnMsIGl0IGRvZXNuJ3QgbWF0dGVyIGlmIGEgdXNlciByZXBvcnRzIHllcyB0byBldmVyIHRyeWluZyAgZS1jaWdhcmV0dGVzLCB0aGV5IGNhbiBzdGlsbCBiZSBhIGN1cnJlbnQgdXNlci4KCgpgYGB7cn0KdGVzdCA8LSB0ZXN0ICU+JQogICAgICAgICBtdXRhdGUoZWNpZ19vbmx5X2V2ZXIgPSBjYXNlX3doZW4oZWNpZ19ldmVyID09IFRSVUUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSksCiAgICAgICAgICBlY2lnX29ubHlfY3VycmVudCA9IGNhc2Vfd2hlbihlY2lnX2N1cnJlbnQgPT0gVFJVRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpLAogICAgICAgIG5vbl9lY2lnX29ubHlfZXZlciA9IGNhc2Vfd2hlbihub25fZWNpZ19ldmVyID09IFRSVUUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSksCiAgbm9uX2VjaWdfb25seV9jdXJyZW50ID0gY2FzZV93aGVuKG5vbl9lY2lnX2N1cnJlbnQgPT0gVFJVRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpLAogICAgICAgICAgICAgICAgICAgIG5vX3VzZSA9IGNhc2Vfd2hlbihub25fZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKQpnbGltcHNlKHRlc3QpCmBgYAoKCgpUYWtlIGEgbWludXRlIHRvIGNoZWNrIHRoYXQgdGhlIHZhbHVlcyBhcmUgd2hhdCB3ZSB3b3VsZCBleHBlY3QuCgpPSywgbm93IHdlIGFyZSBnb2luZyB0byBtYWtlIGEgYEdyb3VwYCB2YXJpYWJsZSBiYXNlZCBvbiB0aGUgbmV3IHZhcmlhYmxlcyB3ZSBqdXN0IG1hZGUgdG8gY2xhc3NpZnkgc3R1ZGVudHMgaW50byBvbmUgb2YgZm91ciBtdXR1YWxseSBleGNsdXNpdmUgYW5kIGV4aGF1c3RpdmUgY2F0ZWdvcmllcy4gSW4gdGhpcyBjYXNlIHdlIHdpbGwgaGF2ZSBhIHBhcnRpY3VsYXIgdmFsdWUgYmFzZWQgb24gb25lIGNvbmRpdGlvbiAqKm9yKiogYW5vdGhlci4gVGhpcyAqKm9yKiogY29uZGl0aW9uYWwgaXMgc3BlY2lmaWVkIGJ5IHRoZSBgfGAgc3ltYm9sLiBPbmx5IG9uZSBvZiB0aGUgY29uZGl0aW9ucyBuZWVkcyB0byBleGlzdCBmb3IgdGhhdCBwYXJ0aWN1bGFyIHZhbHVlLCB3aGVyZWFzIHdoZW4gd2UgdXNlZCB0aGUgYCZgIHN5bWJvbCwgYWxsIG9mIHRoZSBjb25kaXRpb25zIGhhZCB0byBiZSBtZXQuIAoKSWYgYSBzdHVkZW50IGhhcyBldmVyIHRyaWVkIG9yIGN1cnJlbnRseSB1c2VzIGUtY2lnYXJldHRlcywgYnV0IGhhcyBuZXZlciB0cmllZCBvdGhlciB0b2JhY2NvIHByb2R1Y3RzLCB0aGUgdmFsdWUgd2lsbCBiZSBgT25seSBlLWNpZ2FyZXR0ZXNgLiBJZiBhIHN0dWRlbnQgaGFzIGV2ZXIgdHJpZWQgb3IgaXMgYSBjdXJyZW50IHVzZXIgb2Ygb3RoZXIgdG9iYWNjbyBwcm9kdWN0cywgYnV0IGhhcyBuZXZlciB0cmllZCBlLWNpZ2FyZXR0ZXMsIHRoZSB2YWx1ZSB3aWxsIGJlIGBPbmx5IG90aGVyIHByb2R1Y3RzYC4gSWYgdGhlIHZhbHVlIG9mIHRoZSBgbm9fdXNlYCB2YXJpYWJsZSBpcyBzaW1wbHkgYFRSVUVgLCB0aGVuIHRoZSBgR3JvdXBgIHZhcmlhYmxlIHZhbHVlIHdpbGwgYmUgYE5laXRoZXJgLiBGaW5hbGx5LCBpZiBhIHN0dWRlbnQgaGFzIHRyaWVkIG9yIGN1cnJlbnRseSB1c2VzIGJvdGggZS1jaWdhcmV0dGVzIGFuZCBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIHRoZSBgR3JvdXBgIHZhcmlhYmxlIHZhbHVlIHdpbGwgYmUgYENvbWJpbmF0aW9uIG9mIHByb2R1Y3RzYC4gVGh1cyBpbiB0aGlzIGNhc2UgdGhlIHZhbHVlcyBmb3IgdGhlIHVzYWdlIG9mIHRoZSB2YXJpYWJsZXMgYmFzZWQgb24gKipvbmx5KiogdXNpbmcgZS1jaWdhcmV0dGVzIG9yICoqb25seSoqIG90aGVyIHByb2R1Y3RzIHdpbGwgYWxsIGJlIGBGQUxTRWAuIAoKYGBge1J9Cgp0ZXN0IDwtIHRlc3QgJT4lCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKGVjaWdfb25seV9ldmVyID09IFRSVUUgfAogICAgICAgICAgICAgICAgICAgICAgICBlY2lnX29ubHlfY3VycmVudCA9PSBUUlVFIH4gIk9ubHkgZS1jaWdhcmV0dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19vbmx5X2V2ZXIgPT0gVFJVRSB8CiAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfb25seV9jdXJyZW50ID09IFRSVUUgfiAiT25seSBvdGhlciBwcm9kdWN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9fdXNlID09IFRSVUUgfiAiTmVpdGhlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfb25seV9ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19vbmx5X2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX29ubHlfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfb25seV9jdXJyZW50ID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub191c2UgPT0gRkFMU0UgfiAiQ29tYmluYXRpb24gb2YgcHJvZHVjdHMiKSkKCgp0ZXN0ICU+JSBjb3VudChHcm91cCkKCmdsaW1wc2UodGVzdCkKYGBgCgpPSywgbm93IHRoYXQgd2UgaGF2ZSBzZWVuIGhvdyB0aGlzIHdvcmtzIHdpdGggb3VyIHRveSBkYXRhc2V0LCB3ZSB3aWxsIGFwcGx5IG91ciBjb2RlIHRvIG91ciBgbnl0c19kYXRhYC4KCmBgYHtyfQpueXRzX2RhdGEgJTw+JQogICAgICAgICAgICAgbXV0YXRlKGVjaWdfb25seV9ldmVyID0gY2FzZV93aGVuKGVjaWdfZXZlciA9PSBUUlVFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSksCiAgICAgICAgICAgICAgZWNpZ19vbmx5X2N1cnJlbnQgPSBjYXNlX3doZW4oZWNpZ19jdXJyZW50ID09IFRSVUUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSwKICAgICAgICAgICAgbm9uX2VjaWdfb25seV9ldmVyID0gY2FzZV93aGVuKG5vbl9lY2lnX2V2ZXIgPT0gVFJVRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfY3VycmVudCA9PSBGQUxTRSB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBGQUxTRSksCiAgICAgIG5vbl9lY2lnX29ubHlfY3VycmVudCA9IGNhc2Vfd2hlbihub25fZWNpZ19jdXJyZW50ID09IFRSVUUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID09IEZBTFNFIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IEZBTFNFKSwKICAgICAgICAgICAgICAgICAgICAgICAgbm9fdXNlID0gY2FzZV93aGVuKG5vbl9lY2lnX2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfZXZlciA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19jdXJyZW50ID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnQgPT0gRkFMU0UgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKSAlPiUKICAgICAgICAgICAgICAgICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oZWNpZ19vbmx5X2V2ZXIgPT0gVFJVRSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaWdfb25seV9jdXJyZW50ID09IFRSVUUgfiAiT25seSBlLWNpZ2FyZXR0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbl9lY2lnX29ubHlfZXZlciA9PSBUUlVFIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19vbmx5X2N1cnJlbnQgPT0gVFJVRSB+ICJPbmx5IG90aGVyIHByb2R1Y3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub191c2UgPT0gVFJVRSB+ICJOZWl0aGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNpZ19vbmx5X2V2ZXIgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY2lnX29ubHlfY3VycmVudCA9PSBGQUxTRSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9uX2VjaWdfb25seV9ldmVyID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25fZWNpZ19vbmx5X2N1cnJlbnQgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vX3VzZSA9PSBGQUxTRSB+ICJDb21iaW5hdGlvbiBvZiBwcm9kdWN0cyIpKQpgYGAKCgpMYXN0bHksIGl0IGNhbiBiZSB2ZXJ5IGhlbHBmdWwgdG8gaGF2ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHN0dWRlbnRzIHN1cnZleWVkIGVhY2ggeWVhci4gV2UgY2FuIGVhc2lseSBhZGQgYSB2YXJpYWJsZSBmb3IgdGhpcyBieSB1c2luZyB0aGUgYGFkZF9jb3VudCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGlzIHdpbGwgY3JlYXRlIGEgdmFyaWFibGUgY2FsbGVkIGBuYCB3aGljaCB3aWxsIHNob3cgdGhlIHRvdGFsIG51bWJlciBvZiBzdXJ2ZXkgcmVzcG9uc2VzIGZvciB0aGF0IHllYXIuCgpgYGB7cn0Kbnl0c19kYXRhICU8PiUgYWRkX2NvdW50KHllYXIpCmBgYAoKIyMjIyB7LnNjcm9sbGFibGV9CmBgYHtyfQpnbGltcHNlKG55dHNfZGF0YSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBldmFsID0gRkFMU0V9CnNhdmUobnl0c19kYXRhLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZF9kYXRhX3dpdGhfdmFyX2Zvcl9wbG90cy5yZGEiKSkKYGBgCgojIyMgKipRdWVzdGlvbiAxKioKKioqCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojIElmIGluc3RydWN0b3JzIHdhbnQgdG8gc3RhcnQgaGVyZSwgd2UgbmVlZCB0byBsb2FkIHRoZSBkYXRhOgpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWRfZGF0YV93aXRoX3Zhcl9mb3JfcGxvdHMucmRhIikpCmBgYAoKUmVjYWxsIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gaW52ZXN0aWdhdGluZyBob3cgdmFwaW5nIHByb2R1Y3QgdXNlIGhhcyBjb21wYXJlZCB3aXRoIG90aGVyIHRvYmFjY28gdXNlIG92ZXIgdGltZS4gVG8gYW5zd2VyIHRoaXMsIHdlIGZpcnN0IHdhbnQgdG8gZ2V0IGEgc2Vuc2Ugb2YgaG93IHRvYmFjY28gdXNlIGhhcyBjaGFuZ2VkIGluIGdlbmVyYWwgc2luY2UgMjAxNS4gCgpUbyBjcmVhdGUgYSB2aXN1YWxpemF0aW9uIG9mIGhvdyB0b2JhY2NvIHVzYWdlIGhhcyBjaGFuZ2VkIG92ZXIgdGltZSwgd2Ugd2lsbCBmaXJzdCBjb252ZXJ0IHRoZSB1c2FnZSBkYXRhIHRvIGEgcGVyY2VudCB2YWx1ZSBmb3IgZWFjaCB5ZWFyLCB0ZWxsaW5nIHVzIHdoYXQgcGVyY2VudCBvZiBzdHVkZW50IHJlc3BvbmRlbnRzIGZhbGwgaW50byBhIHBhcnRpY3VsYXIgdXNhZ2UgY2F0ZWdvcnkuIFRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGBncm91cF9ieSgpYCBhbmQgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbnMgb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gVGhpcyB3aWxsIGNyZWF0ZSBuZXcgdmFyaWFibGVzIHdoaWNoIHdlIHdpbGwgbmFtZSBgRXZlcmAgYW5kIGBDdXJyZW50YCBiYXNlZCBvbiB0aGUgIHBlcmNlbnRhZ2VzIG9mIGBUUlVFYCB2YWx1ZXMgZm9yIGB0b2JhY2NvX2V2ZXJgIGFuZCBgdG9iYWNjb19jdXJyZW50YCBmb3IgZWFjaCB5ZWFyLiBJbiB0aGlzIGNhc2UgdGhlIGBtZWFuKClgIGZ1bmN0aW9uIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlcyBiYXNlZCBvbiBhbiBhdXRvbWF0aWMgY29udmVyc2lvbiB0aGF0IFIgZG9lcyB3aGVyZSBmb3IgVFJVRS9GQUxTRSB2YXJpYWJsZXMsIGBUUlVFYCBpcyBnaXZlbiBhIHZhbHVlIG9mIG9uZSBhbmQgYEZBTFNFYCBpcyBnaXZlbiBhIHZhbHVlIG9mIHplcm8uIFRoZSBtZWFuIG9mIGEgMC0xIGJpbmFyeSB2YXJpYWJsZSBpcyBqdXN0IHRoZSBwZXJjZW50IG9mIHRoZSB0aW1lIHRoZSB2YWx1ZSBpcyAxLiBOQSB2YWx1ZXMgZG8gbm90IGNvbnRyaWJ1dGUgdG8gdGhlIHRvdGFsIGNvdW50IHdoZW4gd2UgaW5jbHVkZSB0aGUgYXJndW1lbnQgYG5hLnJtID0gVFJVRWAgdG8gb3VyIGZ1bmN0aW9uIGNhbGwuIAoKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBhIHRveSBleGFtcGxlOjwvc3VtbWFyeT4KYGBge3J9CiMgdGhlIHRlc3QgZGF0YSBoYXMgMyBUUlVFIHZhbHVlcyBhbmQgNyBGQUxTRSB2YWx1ZXMKdGVzdCA8LSB0aWJibGUoInZhcjEiID0gYygiVFJVRSIsICJUUlVFIiwgIlRSVUUiLCByZXAoIkZBTFNFIiwgNykpKQp0ZXN0ICU8PiUgbXV0YXRlKHZhcjEgPSBhcy5sb2dpY2FsKHZhcjEpKQp0ZXN0Cgp0ZXN0ICU+JSBzdW1tYXJpemUoUGVyY2VudGFnZSA9IG1lYW4odmFyMSkgKiAxMDApCgoKIyB0aGUgdGVzdCBkYXRhIGhhcyAzIFRSVUUgdmFsdWVzLCAzIEZBTFNFIHZhbHVlcywgYW5kIDQgTkEgdmFsdWUKdGVzdCA8LSB0aWJibGUoInZhcjEiID0gYygiVFJVRSIsICJUUlVFIiwgIlRSVUUiLCByZXAoIkZBTFNFIiwgMyksIHJlcCgiTkEiLCA0KSkpCnRlc3QgJTw+JSBtdXRhdGUodmFyMSA9IGFzLmxvZ2ljYWwodmFyMSkpCnRlc3QKCnRlc3QgJT4lIHN1bW1hcml6ZShQZXJjZW50YWdlID0gbWVhbih2YXIxLCBuYS5ybSA9IFRSVUUpICogMTAwKQpgYGAKPC9kZXRhaWxzPgoKQW5kIG5vdyBiYWNrIHRvIG91ciBkYXRhOgoKYGBge3J9CgpueXRzX2RhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoeWVhcikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKEV2ZXIgPSAobWVhbih0b2JhY2NvX2V2ZXIsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAgICAgICAgICBDdXJyZW50ID0gKG1lYW4odG9iYWNjb19jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSkKYGBgCgpXZSB3aWxsIHVzZSB0aGUgYHBpdm90X2xvbmdlcmAgZnVuY3Rpb24gdG8gdGFrZSBhbGwgY29sdW1ucyBleGNlcHQgeWVhciAoaW4gdGhpcyBjYXNlIHRoZSBgRXZlcmAgYW5kIGBDdXJyZW50YCBjb2x1bW5zKSwgdG8gY3JlYXRlIGEgY29sdW1uIGNhbGxlZCBgVXNlcmAgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIGN1cnJlbnQgY29sdW1uIG5hbWUgaW5mb3JtYXRpb24gYW5kIGEgY29sdW1uIGNhbGxlZCBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2Agd2hpY2ggd2lsbCBjb250YWluIHRoZSBtZWFuIHBlcmNlbnRhZ2UgdmFsdWVzIHRoYXQgd2UganVzdCBjYWxjdWxhdGVkLiBUaGlzIGNvbnZlcnRzIG91ciBkYXRhIGludG8gYSBmb3JtYXQgY2FsbGVkICJsb25nIiBmb3JtYXQuCgpgYGB7cn0KCm55dHNfZGF0YSAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh5ZWFyKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUoRXZlciA9IChtZWFuKHRvYmFjY29fZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgIEN1cnJlbnQgPSAobWVhbih0b2JhY2NvX2N1cnJlbnQsIG5hLnJtID0gVFJVRSkgKiAxMDApKSAlPiUKICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgbmFtZXNfdG8gPSAiVXNlciIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikKYGBgCllvdSBtYXkgaGF2ZSBub3RpY2VkIHRoYXQgb3VyIGRhdGEgaXMgbG9uZ2VyIHRoYW4gaXQgdXNlZCB0byBiZSEgSGVuY2UgdGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uIGBwaXZvdF9sb25nZXIoKWAuIERhdGEgaXMgb2Z0ZW4gZWFzaWVyIHRvIHBsb3Qgd2hlbiBpdCBpcyBpbiB0aGlzIGZvcm1hdC4KICAKTm93IHdlIHdpbGwgdXNlIHRoaXMgZGF0YSB0byBjcmVhdGUgYSBwbG90IHVzaW5nIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4gCgpUaGUgZmlyc3QgdGhpbmcgd2UgZG8gdG8gY3JlYXRlIGEgcGxvdCBpcyBzcGVjaWZ5IHdoYXQgZGF0YSB3ZSBhcmUgdXNpbmcgZm9yIG91ciB4IGF4aXMgYW5kIHkgYXhpcyB3aXRoIHRoZWBhZXMoKWAgYXJndW1lbnQgb2YgdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24uIFRoZW4gd2UgYWRkIGxheWVycyB0byBvdXIgcGxvdCB0aGF0IHNwZWNpZnkgd2hhdCB0eXBlIG9mIHBsb3Qgd2Ugd291bGQgbGlrZSB0byBjcmVhdGUuIFdlIGNhbiB1c2UgdGhlIGBnZW9tX2xpbmUoKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGxpbmVzIGZvciBlYWNoIHR5cGUgb2YgdXNlci4gV2Ugc3BlY2lmeSB0aGF0IHdlIHdhbnQgdG8gdXNlIGRpZmZlcmVudCBsaW5lIHR5cGVzIGZvciBlYWNoIHVzZXIgdXNpbmcgYGFlcygpYC4gV2Ugd2lsbCBhbHNvIGFkZCBwb2ludHMgdG8gb3VyIGxpbmVzIHVzaW5nIHRoZSBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbi4gV2UgY2FuIGFkZCBhZGRpdGlvbmFsIGxheWVycyB0byBzcGVjaWZ5IGNvbG9ycyBhbmQgZGV0YWlscyBhYm91dCBsYWJlbHMgYW5kIGxlZ2VuZHMgZXRjLgogIApgYGB7cn0gIAoKcGxvdDEgPC0gbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZShFdmVyID0gKG1lYW4odG9iYWNjb19ldmVyLCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAgICAgICAgQ3VycmVudCA9IChtZWFuKHRvYmFjY29fY3VycmVudCwgbmEucm0gPSBUUlVFKSAqIDEwMCkpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLXllYXIsIG5hbWVzX3RvID0gIlVzZXIiLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkpICsKICAgIGdlb21fbGluZShhZXMobGluZXR5cGUgPSBVc2VyKSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSwgc2l6ZSA9IDIpICsKICAjIHRoaXMgYWxsb3dzIHVzIHRvIGNob29zZSB3aGF0IHR5cGUgb2YgbGluZSB3ZSB3YW50IGZvciBlYWNoIGxpbmUKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLCAxKSkgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gc3BlY2lmeSBob3cgdGhlIHktYXhpcyBzaG91bGQgYXBwZWFyCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA3MCwgYnkgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsIDcwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsIDcwKSkgKwogICMgdGhpcyBhZGp1c3RzIHRoZSBiYWNrZ3JvdW5kIHN0eWxlIG9mIHRoZSBwbG90CiAgICB0aGVtZV9saW5lZHJhdygpICsKICAjIHRoaXMgbW92ZXMgdGhlIGxlZ2VuZCB0byB0aGUgYm90dG9tIG9mIHRoZSBwbG90IGFuZCByZW1vdmVzIHRoZSB4IGF4aXMgdGl0bGUKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBoYXMgdG9iYWNjbyB1c2UgdmFyaWVkIG92ZXIgdGhlIHllYXJzPyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90MQpgYGAKCk5pY2UhIE5vdyB3ZSBjYW4gc2VlIGhvdyBvdmVyYWxsIHRvYmFjY28gdXNhZ2UgaGFzIGNoYW5nZWQgc2luY2UgMjAxNy4gSXQgYXBwZWFycyB0aGF0IHVzYWdlIGZpcnN0IGRlY3JlYXNlZCBmcm9tIDIwMTUgdG8gMjAxNyBhbmQgdGhlbiBpbmNyZWFzZWQgYSBiaXQgc2luY2UgMjAxNywgc3VycGFzc2luZyB0aGUgbGV2ZWxzIGluIDIwMTUuCgpXaGF0IGFib3V0IGUtY2lnYXJldHRlIHVzZT8gSG93IGhhcyB0aGUgdXNhZ2Ugb2YgZS1jaWdhcmV0dGVzIGNoYW5nZWQgb3ZlciB0aW1lPwoKYGBge3J9CnBsb3QxYSA8LSBueXRzX2RhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoeWVhcikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKEV2ZXIgPSAobWVhbihlY2lnX2V2ZXIsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAgICAgICAgICAgICBDdXJyZW50ID0gKG1lYW4oZWNpZ19jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgbmFtZXNfdG8gPSAiVXNlciIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgKSkgKwogICAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZSA9IFVzZXIpKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gY2hvb3NlIHdoYXQgdHlwZSBvZiBsaW5lIHdlIHdhbnQgZm9yIGVhY2ggbGluZQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgIyB0aGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IGhvdyB0aGUgeS1heGlzIHNob3VsZCBhcHBlYXIKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDYwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsIDYwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCA2MCkpICsKICAjIHRoaXMgYWRqdXN0cyB0aGUgYmFja2dyb3VuZCBzdHlsZSBvZiB0aGUgcGxvdAogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgIyB0aGlzIG1vdmVzIHRoZSBsZWdlbmQgdG8gdGhlIGJvdHRvbSBvZiB0aGUgcGxvdCBhbmQgcmVtb3ZlcyB0aGUgeCBheGlzIHRpdGxlCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICJIb3cgaGFzIGUtY2lnYXJldHRlIHVzZSB2YXJpZWQgb3ZlciB0aGUgeWVhcnM/IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3QxYQpgYGAKSXQgbG9va3MgbGlrZSB0aGUgc2hhcGUgb2YgdGhlIHBsb3QgaXMgdmVyeSBzaW1pbGFyIHRvIHRvYmFjY28gdXNhZ2Ugb3ZlcmFsbC4gV2Ugc2VlIGEgZG93bndhcmQgdHJlbmQgdW50aWwgMjAxNyB3aGVuIHRoZSByYXRlIG9mIGJvdGggY3VycmVudCBhbmQgZXZlciB1c2VycyBpbmNyZWFzZWQuIFJlY2FsbCB0aGF0IHRoaXMgaXMgaW4gYWdyZWVtZW50IHdpdGggdGhlIGFydGljbGVzIHRoYXQgd2UgcmVmZXJlbmNlZCBlYXJsaWVyLiBXZSBjYW4gc2VlIHRoYXQgdGhlIHNsb3BlIGxvb2tzIHN0ZWVwZXIgZm9yIGUtY2lnYXJldHRlIHVzYWdlIGFzIGNvbXBhcmVkIHRvIGFsbCB0b2JhY2NvIHByb2R1Y3RzIChpbmNsdWRpbmcgZS1jaWdhcmV0dGVzKS4KCgpOb3cgbGV0J3MgcGxvdCB0aGlzIGRhdGEgdG9nZXRoZXIgb24gdGhlIHNhbWUgcGxvdC4KCldlIHdpbGwgaGF2ZSBmb3VyIGdyb3VwcyAoZS1jaWdhcmV0dGUgZXZlciB1c2VycywgZS1jaWdhcmV0dGUgY3VycmVudCB1c2VycywgdG9iYWNjbyBldmVyIHVzZXJzLCBhbmQgdG9iYWNjbyBjdXJyZW50IHVzZXJzKSB0byBwbG90LCB0aGVyZWZvcmUsIGl0IHdvdWxkIGJlIHVzZWZ1bCB0byBhZGQgY29sb3IgdG8gb3VyIHBsb3QuIEtlZXAgaW4gbWluZCB0aGF0IGUtY2lnYXJldHRlIHVzZXJzIGFyZSBhIHN1YnNldCBvZiBhbnkgdG9iYWNjbyBwcm9kdWN0IHVzZXJzLgoKT25lIGltcG9ydGFudCB0aGluZyB0byBrZWVwIGluIG1pbmQgd2hlbiBjcmVhdGluZyBwbG90cyBpcyB0aGF0IGluZGl2aWR1YWxzIHdpdGggY29sb3IgYmxpbmRuZXNzIG1heSBoYXZlIGEgZGlmZmljdWx0IHRpbWUgZGlzdGluZ3Vpc2hpbmcgZ3JvdXBzIHdoZW4gY2VydGFpbiBjb2xvciBjaG9pY2VzIGFyZSB1c2VkLiAKCk9uZSBncmVhdCBvcHRpb24gaXMgdG8gdXNlIHRoZSBgdmlyaWRpc2AgcGFja2FnZSwgd2hpY2ggb2ZmZXJzIGNvbG9yIHBhbGV0dGVzIHdpdGggY29sb3JzIHRoYXQgYXJlIHN0aWxsIGRpc3Rpbmd1aXNoYWJsZSBieSBpbmRpdmlkdWFscyB3aXRoIG1vc3QgZm9ybXMgb2YgY29sb3IgYmxpbmRuZXNzLiAKCldlIGNhbiBjaG9vc2Ugd2hpY2ggY29sb3JzIHdlIHdhbnQgdG8gdXNlIGJ5IHVzaW5nIHRoZSBgc2hvd19jb2woKWAgZnVuY3Rpb24gb2YgdGhlIGBzY2FsZXNgIHBhY2thZ2UuCgpIZXJlIGFyZSBzb21lIGNvbG9yIG9wdGlvbnM6CmBgYHtyfQoKc2NhbGVzOjpzaG93X2NvbCh2aXJpZGlzX3BhbCgpKDYpKQp2X2NvbG9ycyA9ICB2aXJpZGlzKDYpW2MoMSwgNCldCmBgYAoKV2Ugd2lsbCBzZWxlY3QgdGhlIGZpcnN0IGFuZCBmb3VydGggY29sb3JzIGZvciBvdXIgcGxvdC4gVG8gYWRkIHRoZXNlIHNwZWNpZmljIGNvbG9ycyB3ZSB3aWxsIHVzZSB0aGUgYHNjYWxlX2NvbG9yX21hbnVhbCgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCgpXZSB3aWxsIGNhbGN1bGF0ZSB0aGUgbWVhbiBldmVyIGFuZCBjdXJyZW50IHVzYWdlIHBlcmNlbnRhZ2VzIGZvciBzdHVkZW50cyB3aG8gdXNlZCBlLWNpZ2FyZXR0ZXMgb3IgYW55IHRvYmFjY28gcHJvZHVjdHMgKGluY2x1ZGluZyBlLWNpZ2FyZXR0ZXMpIGZvciBlYWNoIHllYXIgYWdhaW4gdXNpbmcgdGhlIGBncm91cF9ieSgpYCBhbmQgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbnMuIFdlIHdpbGwgYWdhaW4gdXNlIHRoZSBgcGl2b3RfbG9uZ2VyYCBmdW5jdGlvbiB0byBjb252ZXJ0IG91ciBkYXRhIHRvIGxvbmcgZm9ybWF0LiBXZSB3aWxsIGFsc28gdXNlIHRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byBjcmVhdGUgdHdvIHZhcmlhYmxlcyBmcm9tIG9uZSBvZiB0aGUgdmFyaWFibGVzLiBUaGlzIGlzIGRvbmUgYnkgc2VwYXJhdGluZyBieSwgaW4gdGhpcyBjYXNlLCBhbiB1bmRlcnNjb3JlLiAKCgpgYGB7cn0Kbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZSgiRXZlcl9BbnkgVG9iYWNjbyBQcm9kdWN0IFxuIChpbmNsdWRpbmcgZS1jaWdhcmV0dGVzKSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbih0b2JhY2NvX2V2ZXIsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAgICAgICAgICAgICAiQ3VycmVudF9BbnkgVG9iYWNjbyBQcm9kdWN0IFxuIChpbmNsdWRpbmcgZS1jaWdhcmV0dGVzKSIgPSAgIAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKHRvYmFjY29fY3VycmVudCwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJFdmVyX0UtY2lnYXJldHRlcyIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihlY2lnX2V2ZXIsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAgICAgICAgICAgICAiQ3VycmVudF9FLWNpZ2FyZXR0ZXMiID0gCiAgICAgICAgICAgICAgICAgICAgICAgKG1lYW4oZWNpZ19jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgCiAgICAgICAgICAgbmFtZXNfdG8gPSAiVXNlciIsIAogICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBzZXBhcmF0ZShVc2VyLCBpbnRvID0gYygiVXNlciIsICJQcm9kdWN0IiksIHNlcCA9ICJfIikgJT4lCiAgaGVhZCgpCgoKcGxvdDF0IDwtIG55dHNfZGF0YSAlPiUKICAgIGdyb3VwX2J5KHllYXIpICU+JQogICAgc3VtbWFyaXplKCJFdmVyX0FueSBUb2JhY2NvIFByb2R1Y3QgXG4gKGluY2x1ZGluZyBlLWNpZ2FyZXR0ZXMpIiA9IAogICAgICAgICAgICAgICAgKG1lYW4odG9iYWNjb19ldmVyLCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAiQ3VycmVudF9BbnkgVG9iYWNjbyBQcm9kdWN0IFxuIChpbmNsdWRpbmcgZS1jaWdhcmV0dGVzKSIgPSAKICAgICAgICAgICAgICAgIChtZWFuKHRvYmFjY29fY3VycmVudCwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgIkV2ZXJfRS1jaWdhcmV0dGVzIiA9IAogICAgICAgICAgICAgICAgKG1lYW4oZWNpZ19ldmVyLCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAgIkN1cnJlbnRfRS1jaWdhcmV0dGVzIiA9IAogICAgICAgICAgICAgICAgKG1lYW4oZWNpZ19jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAteWVhciwgCiAgICAgICAgICAgbmFtZXNfdG8gPSAiVXNlciIsIAogICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBzZXBhcmF0ZShVc2VyLCAKICAgICAgICAgICBpbnRvID0gYygiVXNlciIsICJQcm9kdWN0IiksIAogICAgICAgICAgICBzZXAgPSAiXyIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0geWVhciwgCiAgICAgICAgICAgICAgIHkgPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2AsCiAgICAgICAgICAgY29sb3IgPSBQcm9kdWN0KSkgKwogICAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZSA9IFVzZXIpKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gY2hvb3NlIHdoYXQgdHlwZSBvZiBsaW5lIHdlIHdhbnQgZm9yIGVhY2ggbGluZQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgIyB3ZSB3YW50IHB1cnBsZSBhc3NvY2lhdGVkIHdpdGggZS1jaWdhcmV0dGVzIHRvIGJlIGNvbnNpc3RlbnQgd2l0aCBsYXRlciBwbG90cwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSByZXYodl9jb2xvcnMpKSArCiAgIyB0aGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IGhvdyB0aGUgeS1heGlzIHNob3VsZCBhcHBlYXIKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDYwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsIDYwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCA2MCkpICsKICAjIHRoaXMgYWRqdXN0cyB0aGUgYmFja2dyb3VuZCBzdHlsZSBvZiB0aGUgcGxvdAogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgIyB0aGlzIG1vdmVzIHRoZSBsZWdlbmQgdG8gdGhlIGJvdHRvbSBvZiB0aGUgcGxvdCBhbmQgcmVtb3ZlcyB0aGUgeCBheGlzIHRpdGxlCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICJIb3cgaGFzIHRvYmFjY28gdXNlIHZhcmllZCBvdmVyIHRoZSB5ZWFycz8iLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKcGxvdDF0CmBgYAoKV2Ugc2VlIGFuIGluY3JlYXNlIGluIGFsbCBjYXRlZ29yaWVzIHN0YXJ0aW5nIGluIDIwMTcsIGJ1dCB0aGUgcmF0ZSBvZiBpbmNyZWFzZSBpcyBoaWdoZXIgZm9yIHN0dWRlbnRzIHVzaW5nIG9ubHkgZS1jaWdhcmV0dGVzIChjdXJyZW50IG9yIGV2ZXIgdXNlcnMpLCBhcyBzaG93biBieSB0aGUgaGlnaGVyIHNsb3BlIG9mIHRoZSBlLWNpZ2FyZXR0ZSBsaW5lcy4KCkluIHRoZSBhYm92ZSBwbG90cywgdGhlICJBbnkgdG9iYWNjbyBwcm9kdWN0IiBncm91cHMgaW5jbHVkZSBpbmRpdmlkdWFscyBpbiB0aGUgIkUtY2lnYXJldHRlIG9ubHkiIGdyb3Vwcy4gTm93IGxldCdzIHBsb3Qgc3R1ZGVudHMgaW4gdHdvIG11dHVhbGx5IGV4Y2x1c2l2ZSBncm91cHMgb24gdGhlIHNhbWUgcGxvdDogdGhvc2Ugd2hvIHJlcG9ydGVkIGVpdGhlciB1c2luZyBvbmx5IGUtY2lnYXJldHRlcyBvciBvbmx5IG90aGVyIHRvYmFjY28gcHJvZHVjdHMgKGJlc2lkZXMgZS1jaWdhcmV0dGVzKSwgYnV0IG5vdCBib3RoLiAKCldlIHdpbGwgY2FsY3VsYXRlIHRoZSBtZWFuIGV2ZXIgYW5kIGN1cnJlbnQgdXNhZ2UgcGVyY2VudGFnZXMgZm9yIHN0dWRlbnRzIGluIHRoZXNlIHR3byBtdXR1YWxseSBleGNsdXNpdmUgZ3JvdXBzLCBhZ2FpbiB1c2luZyB0aGUgYGdyb3VwX2J5KClgIGZ1bmN0aW9uIGFuZCB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbi4gV2Ugd2lsbCBhZ2FpbiB1c2UgdGhlIGBwaXZvdF9sb25nZXJgIGZ1bmN0aW9uIHRvIGNvbnZlcnQgb3VyIGRhdGEgdG8gbG9uZyBmb3JtYXQuIFdlIHdpbGwgYWxzbyBhZ2FpbiB1c2UgdGhlIGBzZXBhcmF0ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlIHRvIGNyZWF0ZSB0d28gdmFyaWFibGVzIGZyb20gb25lIHZhcmlhYmxlLiBUaGlzIGlzIGRvbmUgYnkgc2VwYXJhdGluZyBieSwgaW4gdGhpcyBjYXNlLCBhIHNwYWNlLiAKCmBgYHtyfQoKbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZSgiRXZlcl9FLWNpZ2FyZXR0ZSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihlY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X0UtY2lnYXJldHRlIiA9IAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKGVjaWdfb25seV9jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkV2ZXJfTm9uLWUtY2lnYXJldHRlIiA9IAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKG5vbl9lY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X05vbi1lLWNpZ2FyZXR0ZSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihub25fZWNpZ19vbmx5X2N1cnJlbnQsIG5hLnJtID0gVFJVRSkgKiAxMDApKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC15ZWFyLCAKICAgICAgICAgICBuYW1lc190byA9ICJVc2VyIiwgCiAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogIHRpZHlyOjpzZXBhcmF0ZShVc2VyLCBpbnRvID0gYygiVXNlciIsICJQcm9kdWN0IiksIHNlcCA9ICJfIikgJT4lCiAgaGVhZCgpCgpwbG90MWMgPC0gbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZSgiRXZlcl9FLWNpZ2FyZXR0ZSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihlY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X0UtY2lnYXJldHRlIiA9IAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKGVjaWdfb25seV9jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkV2ZXJfTm9uLWUtY2lnYXJldHRlIiA9IAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKG5vbl9lY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X05vbi1lLWNpZ2FyZXR0ZSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihub25fZWNpZ19vbmx5X2N1cnJlbnQsIG5hLnJtID0gVFJVRSkgKiAxMDApKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC15ZWFyLCAKICAgICAgICAgICBuYW1lc190byA9ICJVc2VyIiwgCiAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogIHNlcGFyYXRlKFVzZXIsIGludG8gPSBjKCJVc2VyIiwgIlByb2R1Y3QiKSwgc2VwID0gIl8iKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2AsIGNvbG9yID0gUHJvZHVjdCkpICsKICAgIGdlb21fbGluZShhZXMobGluZXR5cGUgPSBVc2VyKSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSwgc2l6ZSA9IDIpICsKICAjIHRoaXMgYWxsb3dzIHVzIHRvIGNob29zZSB3aGF0IHR5cGUgb2YgbGluZSB3ZSB3YW50IGZvciBlYWNoIGxpbmUKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLCAxKSkgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gc3BlY2lmeSBob3cgdGhlIHktYXhpcyBzaG91bGQgYXBwZWFyCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAzMCwgYnkgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLCAzMCwgYnkgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgMzApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgIyB0aGlzIGFkanVzdHMgdGhlIGJhY2tncm91bmQgc3R5bGUgb2YgdGhlIHBsb3QKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICMgdGhpcyBtb3ZlcyB0aGUgbGVnZW5kIHRvIHRoZSBib3R0b20gb2YgdGhlIHBsb3QgYW5kIHJlbW92ZXMgdGhlIHggYXhpcyB0aXRsZQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPQoiSG93IGhhcyB1c2Ugb2Ygb25seSBlLWNpZ2FyZXR0ZXMgYW5kCm9ubHkgdG9iYWNjbyBwcm9kdWN0cyBiZXNpZGVzIGUtY2lnYXJldHRlcyB2YXJpZWQgb3ZlciB0aW1lPyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90MWMKYGBgCgpWZXJ5IGludGVyZXN0aW5nISBXZSBjYW4gc2VlIGZyb20gdGhpcyBwbG90IHRoYXQgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMgd2hvIGhhZCBjdXJyZW50bHkgdXNlZCAob3IgZXZlciB0cmllZCkgb25seSBlLWNpZ2FyZXR0ZXMgZ3JlYXRseSBpbmNyZWFzZWQgc3RhcnRpbmcgaW4gMjAxNywgd2hpbGUgaW4gY29udHJhc3QgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMgd2hvIGhhZCBldmVyIHRyaWVkIG9ubHkgbm9uLWUtY2lnYXJldHRlIHRvYmFjY28gcHJvZHVjdHMgYWN0dWFsbHkgZGltaW5pc2hlZCBvdmVyIHRpbWUuIEluIGZhY3QsIHdlIGNhbiBzZWUgdGhhdCBpbiAyMDE5IHRoZSBwZXJjZW50YWdlIG9mIHN0dWRlbnRzIHdobyB3ZXJlIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlcnMgc3VycGFzc2VkIHRoZSBwZXJjZW50YWdlIHRoYXQgaGFkIHRyaWVkIGEgbm9uLWUtY2lnYXJldHRlIHByb2R1Y3QgZXZlbiBqdXN0IG9uY2UuIAoKClJlY2FsbCB0aGF0IHdlIG1hZGUgYSB2YXJpYWJsZSBjYWxsZWQgYEdyb3VwYCB0aGF0IGlkZW50aWZpZWQgc3R1ZGVudHMgd2hvIHVzZWQgZWl0aGVyIGp1c3QgZS1jaWdhcmV0dGUgcHJvZHVjdHMsIGp1c3Qgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyAoYmVzaWRlcyBlLWNpZ2FyZXR0ZXMpLCBvciBzdHVkZW50cyB3aG8gdXNlZCBib3RoIGUtY2lnYXJldHRlcyBhbmQgc29tZSBvdGhlciB0eXBlIG9mIHRvYmFjY28gcHJvZHVjdC4KCmBgYHtyfQpueXRzX2RhdGEgJT4lCiAgY291bnQoR3JvdXApCmBgYAoKV2Ugd2lsbCBub3cgbWFrZSBhIHBsb3Qgb3ZlciB0aW1lIG9mIGVhY2ggb2YgdGhlc2UgZ3JvdXBzLiBTaW5jZSB3ZSB3aWxsIGhhdmUgNCB0b3RhbCBncm91cHMsIHdlIHdpbGwgdXNlIDQgb2YgdGhlIHZpcmlkaXMgY29sb3JzLgpOb3RpY2UsIHRoYXQgaW4gdGhpcyBjYXNlIHdlIGFyZSBncm91cGluZyBieSB0aHJlZSB2YXJpYWJsZXMgYnkgc2ltcGx5IHNlcGFyYXRpbmcgdGhlIHZhcmlhYmxlcyB0aGF0IHdlIHdhbnQgdG8gZ3JvdXAgYnkgd2l0aCBhIGNvbW1hIGluIG91ciBgZ3JvdXBfYnkoKWAgZnVuY3Rpb24gbGlrZSB0aGlzOiBgZ3JvdXBfYnkoR3JvdXAsIHllYXIsIG4pYC4gCgpgYGB7cn0KCm55dHNfZGF0YSAlPiUKICBncm91cF9ieShHcm91cCwgeWVhciwgbikgJT4lCiAgc3VtbWFyaXNlKGdyb3VwX2NvdW50ID0gbigpKSAlPiUKICBtdXRhdGUoIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiID0gZ3JvdXBfY291bnQgLyBuICogMTAwKSAlPiUKICBoZWFkKCkKCnZfY29sb3JzID0gIHZpcmlkaXMoNSlbMTo0XQoKbnl0c19kYXRhICU+JQogIGdyb3VwX2J5KEdyb3VwLCB5ZWFyLCBuKSAlPiUKICBzdW1tYXJpc2UoZ3JvdXBfY291bnQgPSBuKCkpICU+JQogIG11dGF0ZSgiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIgPSBncm91cF9jb3VudCAvIG4gKiAxMDApICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2AsIGNvbG9yID0gR3JvdXApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICB0aGVtZV9saW5lZHJhdygpICsKICBsYWJzKHggPSAiWWVhciIpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBtYWpvcml0eSBvZiBzdHVkZW50cyBkaWQgbm90IHJlcG9ydCB1c2luZyBhbnkgdG9iYWNjbyBwcm9kdWN0cy4gT2YgdGhlIHN0dWRlbnRzIHRoYXQgZGlkIHJlcG9ydCB1c2luZyB0b2JhY2NvIHByb2R1Y3RzLCB0aGUgbWFqb3JpdHkgb2YgdGhlIHN0dWRlbnRzIHVzZWQgYm90aCBlLWNpZ2FyZXR0ZXMgYW5kIHNvbWUgb3RoZXIgdG9iYWNjbyBwcm9kdWN0LiBBZ2FpbiwgYSBtdWNoIGxhcmdlciBwZXJjZW50YWdlIHJlcG9ydGVkIHVzaW5nIG9ubHkgZS1jaWdhcmV0dGVzIHJhdGhlciB0aGFuIG9ubHkgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyBpbiAyMDE5LgoKV2Ugd2lsbCBmdXJ0aGVyIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGUtY2lnYXJldHRlIHVzYWdlIGFuZCBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIGEgYml0IGxhdGVyIGluIHRoZSBjYXNlIHN0dWR5LgoKCiMjIyAqKlF1ZXN0aW9uIDIqKgoqKioKCk5vdyB3ZSB3YW50IHRvIGxvb2sgaG93IGUtY2lnYXJldHRlIHNtb2tpbmcgcmF0ZXMgY29tcGFyZSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIGFjcm9zcyB0aW1lLiAKCgpXZSB3aWxsIGNhbGN1bGF0ZSB0aGUgcGVyY2VudCBldmVyIGFuZCBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXJzIGZvciBlYWNoIHllYXIgYW5kIHNleCBjYXRlZ29yeSBhZ2FpbiB1c2luZyB0aGUgYGdyb3VwX2J5KClgIGZ1bmN0aW9uIGFuZCB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbi4gIFdlIHdpbGwgYWdhaW4gdXNlIHRoZSBgcGl2b3RfbG9uZ2VyYCBmdW5jdGlvbiB0byBjb252ZXJ0IG91ciBkYXRhIHRvIGxvbmcgZm9ybWF0LiAKCkFzIGRpc2N1c3NlZCBhYm92ZSwgd2UgYWNrbm93bGVkZ2UgdGhhdCB3aGlsZSBbZ2VuZGVyXShodHRwczovL3d3dy5nZW5kZXJzcGVjdHJ1bS5vcmcvcXVpY2stbGlua3MvdW5kZXJzdGFuZGluZy1nZW5kZXIvKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBbc2V4XShodHRwczovL3d3dy53aG8uaW50L2dlbm9taWNzL2dlbmRlci9lbi9pbmRleDEuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBhcmUgbm90IGFjdHVhbGx5IGJpbmFyeSwgdGhlIGRhdGEgdXNlZCBpbiB0aGlzIGFuYWx5c2lzIG9ubHkgY29udGFpbiBpbmZvcm1hdGlvbiBmb3IgZ3JvdXBzIG9mIGluZGl2aWR1YWxzIHdobyBhbnN3ZXJlZCB0aGUgc3VydmV5IHF1ZXN0aW9ucyBhcyBtYWxlIG9yIGZlbWFsZS4gRm9yIGluZGl2aWR1YWxzIHRoYXQgaGF2ZSBOQSB2YWx1ZXMsIGl0IGlzIHVuY2xlYXIgaWYgdGhlIHF1ZXN0aW9uIHdhcyBub3QgYW5zd2VyZWQgb3IgaWYgdGhlIGluZGl2aWR1YWwgaWRlbnRpZmllcyBhcyBub24tYmluYXJ5LiBCZWNhdXNlIG9mIHRoaXMgdW5jZXJ0YWludHksIHdlIHdpbGwgZmlsdGVyIHRoZXNlIGluZGl2aWR1YWxzIG91dC4gCgpgYGB7cn0KCnZfY29sb3JzID0gIHZpcmlkaXMoNilbYygxLCA0KV0KCm55dHNfZGF0YSAlPiUKICAgICBmaWx0ZXIoIWlzLm5hKFNleCkpICU+JQogICAgIGdyb3VwX2J5KHllYXIsIFNleCkgJT4lCiAgICAgc3VtbWFyaXplKEV2ZXIgPSAobWVhbihFRUxDSUdULCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAgQ3VycmVudCA9IChtZWFuKENFTENJR1QsIG5hLnJtID0gVFJVRSkgKiAxMDApKSAlPiUKICAgICBwaXZvdF9sb25nZXIoY29scyA9IEV2ZXI6Q3VycmVudCwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiVXNlciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICAgaGVhZCgpCgpwbG90MiA8LSBueXRzX2RhdGEgJT4lCiAgICAgZmlsdGVyKCFpcy5uYShTZXgpKSAlPiUKICAgICBncm91cF9ieSh5ZWFyLCBTZXgpICU+JQogICAgIHN1bW1hcml6ZShFdmVyID0gKG1lYW4oRUVMQ0lHVCwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgIEN1cnJlbnQgPSAobWVhbihDRUxDSUdULCBuYS5ybSA9IFRSVUUpICogMTAwKSkgJT4lCiAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBFdmVyOkN1cnJlbnQsCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlVzZXIiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgY29sb3IgPSBTZXgpKSArCiAgICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlID0gVXNlcikpICsKICAgIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSwgc2l6ZSA9IDIpICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiSG93IGRvZXMgZS1jaWdhcmV0dGUgdXNhZ2UgY29tcGFyZSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzPyIsCiAgICAgICAgIHN1YnRpdGxlID0gIkN1cnJlbnQgYW5kIGV2ZXIgdXNlcnMgYnkgc2V4IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3QyCmBgYAoKSXQgbG9va3MgbGlrZSB0aGUgcmF0ZXMgYXJlIGZhaXJseSBzaW1pbGFyIGJldHdlZW4gdGhlIHNleGVzLCBob3dldmVyIHRoZSByYXRlIGZvciBtYWxlcyBhcHBlYXJzIHRvIGJlIGNvbnNpc3RlbnRseSBoaWdoZXIgYWNyb3NzIHRpbWUuCgpgYGB7ciwgZWNobz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZ2dzYXZlKGhlcmU6OmhlcmUoImltZyIsICJwbG90Mi5wbmciKSkKYGBgCgojIyMgKipRdWVzdGlvbiAzKioKKioqCgpXZSBhcmUgYWxzbyBpbnRlcmVzdGVkIGluIHdoYXQgdmFwaW5nIGJyYW5kcyBhbmQgZmxhdm9ycyBhcHBlYXIgdG8gYmUgdXNlZCB0aGUgbW9zdCBmcmVxdWVudGx5LiBPbmx5IHRoZSAyMDE5IGRhdGEgc2V0IGhhcyB0aGlzIGluZm9ybWF0aW9uLiBUaGVyZWZvcmUsIHdlIHdpbGwgZmlsdGVyIGZvciBqdXN0IHRoaXMgeWVhciB1c2luZyB0aGUgYGZpbHRlcigpYCBmdW5jdGlvbiBvZiAgdGhlIGBkcGx5cmAgcGFja2FnZS4gV2Ugd2lsbCB1c2UgdGhlIGBzdW1tYXJpemUoKWAgZnVuY3Rpb24gc2xpZ2h0bHkgZGlmZmVyZW50bHkgdGhpcyB0aW1lLCB0byBjYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiBzdHVkZW50cyB1c2luZyBlYWNoIGJyYW5kIHVzaW5nIHRoZSBgbigpYCBmdW5jdGlvbiBhbmQgdGhlIGBzdW0oKWAgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBwZXJjZW50IGZvciBlYWNoIGJyYW5kIGJhc2VkIG9uIHRoZSBjb3VudHMuIFdlIHdpbGwgYWxzbyByZW9yZGVyIHRoZSBmYWN0b3IgbGV2ZWxzIGZvciB0aGUgYnJhbmQgbmFtZXMgc28gdGhhdCB0aGV5IGFyZSBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIHBlcmNlbnQgdXNlLCB1c2luZyB0aGUgYGZjdF9yZW9yZGVyKClgIGZ1bmN0aW9uIGZyb20gYGRwbHlyYC4gVGhpcyB3aWxsIG1ha2UgdGhlbSBhcHBlYXIgaW4gZGVjcmVhc2luZyBvcmRlciBvZiBwZXJjZW50IHVzZSBvbiB0aGUgcGxvdC4KCldlIHdpbGwgbWFrZSBhIGJhciBwbG90IHRoaXMgdGltZSBieSB1c2luZyBgZ2VvbV9iYXJgLiBJbXBvcnRhbnRseSB3ZSBhc3NpZ24gdGhlIGBzdGF0YCBhcmd1bWVudCB0byBgaWRlbnRpdHlgLCBzbyB0aGF0IHdlIGFyZSB1c2luZyB0aGUgcGVyY2VudGFnZXMgdGhhdCB3ZSBjYWxjdWxhdGVkIG5vdCB0aGUgY291bnRzIHdoaWNoIGlzIHdoYXQgaXMgdXNlZCBieSBkZWZhdWx0LiBXaGVuIGNvbG9yIGluIHNwZWNpZmllZCBvdXRzaWRlIG9mIHRoZSBgYWVzKClgIGFyZ3VtZW50LCB0aGlzIGRldGVybWluZXMgdGhlIGJvcmRlciBjb2xvciBvZiB0aGUgYmFycywgd2hpY2ggaW4gdGhpcyBjYXNlIHdpbGwgYmUgYmxhY2suCgpgYGB7cn0KCm55dHNfZGF0YSAlPiUKICAgIGZpbHRlcih5ZWFyID09IDIwMTkpICU+JQogICAgZ3JvdXBfYnkoYnJhbmRfZWNpZykgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKGJyYW5kX2VjaWcpKSAlPiUKICBzdW1tYXJpemUobiA9IG4oKSkgJT4lCiAgICBtdXRhdGUodG90YWwgPSBzdW0obiksCiAgICAgICAgICAgUGVyY2VudCA9IG4gKiAxMDAgLyB0b3RhbCkgJT4lCiAgICBtdXRhdGUoYnJhbmRfZWNpZyA9IGZjdF9yZW9yZGVyKGJyYW5kX2VjaWcsIGRlc2MoUGVyY2VudCkpKQoKCnBsb3QzIDwtIG55dHNfZGF0YSAlPiUKICAgIGZpbHRlcih5ZWFyID09IDIwMTkpICU+JQogICAgZ3JvdXBfYnkoYnJhbmRfZWNpZykgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKGJyYW5kX2VjaWcpKSAlPiUKICBzdW1tYXJpemUobiA9IG4oKSkgJT4lCiAgICBtdXRhdGUodG90YWwgPSBzdW0obiksCiAgICAgICAgICAgUGVyY2VudCA9IG4gKiAxMDAgLyB0b3RhbCkgJT4lCiAgICBtdXRhdGUoYnJhbmRfZWNpZyA9IGZjdF9yZW9yZGVyKGJyYW5kX2VjaWcsIGRlc2MoUGVyY2VudCkpKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IGJyYW5kX2VjaWcsIHkgPSBQZXJjZW50LCBmaWxsID0gYnJhbmRfZWNpZykpICsKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICJXaGF0IHZhcGluZyBicmFuZHMgYXBwZWFyIHRvIGJlIHVzZWQgdGhlIG1vc3QgZnJlcXVlbnRseT8iLAogICAgICAgICBzdWJ0aXRsZSA9ICJCcmFuZCBvZiBlLWNpZ2FyZXR0ZSBtb3N0IGZyZXF1ZW50bHkgdXNlZCBpbiB0aGUgbGFzdCAzMCBkYXlzICgyMDE5KSIsCiAgICAgICAgIHkgPSAiJSBvZiBlLWNpZ2FyZXR0ZSB1c2VycyByZXNwb25kaW5nIikKCnBsb3QzCmBgYAoKSnV1bCBhcHBlYXJzIHRvIGJlIHRoZSBtb3N0IHdpZGVseSB1c2VkIGJyYW5kLiBUaGlzIGlzIGluIGFncmVlbWVudCB3aXRoIGEgcmVjZW50IFthcnRpY2xlXShodHRwczovL3RvYmFjY29jb250cm9sLmJtai5jb20vY29udGVudC90b2JhY2NvY29udHJvbC8yOC8yLzE0Ni5mdWxsLnBkZiksIHdob3NlIG1vc3QgcmVjZW50IGRhdGEgd2FzIGZyb20gMjAxNzoKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSJIdWFuZyBKLCBEdWFuIFosIEt3b2sgSiwgZXQgYWwuIFRvYiBDb250cm9sIDIwMTk7Mjg6MTQ24oCTMTUxLiIsIG91dC53aWR0aCA9ICcxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIkh1YW5nSl9EdWFuWl9Ld29rSl9ldF9hbF9Ub2JhY2NvQ29udHJvbF9GaWd1cmUxLnBuZyIpKQpgYGAKCldlIGFyZSBhbHNvIGludGVyZXN0ZWQgaW4gaG93IHRoZSB1c2FnZSBvZiBkaWZmZXJlbnQgZmxhdm9ycyBoYXMgY2hhbmdlZCBvdmVyIHRpbWUuIAoKClRvIGV2YWx1YXRlIHRoaXMgd2Ugd2lsbCBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMgdXNpbmcgZWFjaCBmbGF2b3IgZWFjaCB5ZWFyIC0gdGhpcyBpbmNsdWRlcyB1c2FnZSBvZiBhbnkgdHlwZSBvZiBmbGF2b3JlZCB0b2JhY2NvIHByb2R1Y3QuIFdlIHdpbGwgZXhjbHVkZSAyMDE1IGRhdGEsIGFzIG5vIHNwZWNpZmljIGZsYXZvciBxdWVzdGlvbnMgd2VyZSBhc2tlZCBhdCB0aGF0IHRpbWUuCgpSZWNhbGwgdGhhdCBgTkFgIHZhbHVlcyBhcmUgbm90IGluY2x1ZGVkIGluIGNhbGN1bGF0aW5nIHRoZSB0b3RhbCBjb3VudCBmb3Igb3VyIHBlcmNlbnRhZ2VzLiBIb3dldmVyIGFsbCBvZiB0aGVzZSBmbGF2b3IgcXVlc3Rpb25zIGhhZCBjb21wbGV0ZSByZXBvcnRpbmcgYW5kIGRpZCBub3QgaGF2ZSBgTkFgIHZhbHVlcy4gVGhlcmVmb3JlLCB0aGVzZSB2YWx1ZXMgcmVmbGVjdCB0aGUgcGVyY2VudGFnZSBvZiBzdHVkZW50cyByZXBvcnRpbmcgdXNpbmcgYSBwYXJ0aWN1bGFyIGZhdm9yIG91dCBvZiBhbGwgc3R1ZGVudHMgc3VydmV5ZWQgKGluY2x1ZGluZyB0aG9zZSB0aGF0IGRpZCBub3QgdXNlIGFueSB0b2JhY2NvIHByb2R1Y3RzKS4gQWxzbyBzdHVkZW50cyB3ZXJlIGFsbG93ZWQgdG8gc2VsZWN0IG1vcmUgdGhhbiBvbmUgZmxhdm9yLiBZb3UgY2FuIHNlZSB3aGV0aGVyIHRoZXNlIHZhcmlhYmxlcyBoYWQgY29tcGxldGUgcmVwb3J0aW5nIGJ5IGNoZWNraW5nIHRoZSBgTkFgIHZhbHVlcyB1c2luZyB0aGUgYmFzZSBgc3VtbWFyeWAgZnVuY3Rpb24uIEFsdGVybmF0aXZlbHkgeW91IGNhbiBjcmVhdGUgYSB2aXN1YWwgcmVwcmVzZW50YXRpb24gdXNpbmcgdGhlIGB2aXNfbWlzcygpYCBmdW5jdGlvbiBvZiB0aGUgYG5hbmlhcmAgcGFja2FnZS4KCiMjIyMgey5zY3JvbGxhYmxlfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpueXRzX2RhdGEgJT4lCiAgZmlsdGVyKHllYXIgIT0gMjAxNSkgJT4lCiAgc3VtbWFyeSgpCmBgYAojIyMjCgoKYGBge3J9Cm55dHNfZGF0YSAlPiUKICBmaWx0ZXIoeWVhciAhPSAyMDE1KSAlPiUKICBzZWxlY3QobWVudGhvbDphbGNvaG9saWNfZHJpbmspICU+JQogIHZpc19taXNzKCkKYGBgCgoKVGhlIHBsb3QgYWJvdmUgY29uZmlybXMgdGhhdCB0aGVzZSB2YXJpYWJsZXMgaGF2ZSBubyBgTkFgIHZhbHVlcyAoYmVjYXVzZSBhbGwgZmllbGRzIGluZGljYXRlIDEwMCUgb2YgZGF0YSBpcyBwcmVzZW50KS4KCmBgYHtyfQpwbG90NCA8LSBueXRzX2RhdGEgJT4lCiAgZmlsdGVyKHllYXIgIT0gMjAxNSkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgIHN1bW1hcml6ZShNZW50aG9sID0gKG1lYW4obWVudGhvbCkgKiAxMDApLAogICAgICAgYENsb3ZlIG9yIFNwaWNlYCA9IChtZWFuKGNsb3ZlX3NwaWNlKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgIEZydWl0ID0gKG1lYW4oZnJ1aXQpICogMTAwKSwKICAgICAgICAgICAgICBDaG9jb2xhdGUgPSAobWVhbihjaG9jb2xhdGUpICogMTAwKSwKICAgICAgYEFsY29ob2xpYyBEcmlua2AgPSAobWVhbihhbGNvaG9saWNfZHJpbmspICogMTAwKSwKYENhbmR5L0Rlc3NlcnRzL1N3ZWV0c2AgPSAobWVhbihjYW5keV9kZXNzZXJ0X3N3ZWV0cykgKiAxMDApLAogICAgICAgICAgICAgICAgICBPdGhlciA9IChtZWFuKG90aGVyKSAqIDEwMCkpICU+JQogICAgICBwaXZvdF9sb25nZXIoY29scyA9IC15ZWFyLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiRmxhdm9yIiwKICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogIHJlbmFtZShZZWFyID0geWVhcikgJT4lCgogZ2dwbG90KGFlcyh5ID0gYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgLAogICAgICAgICAgICB4ID0gWWVhciwKICAgICAgICAgZmlsbCA9IHJlb3JkZXIoRmxhdm9yLCBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApKSkgKwpnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgdGhlbWVfbGluZWRyYXcoKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQoIkZsYXZvciIpKSArCiAgbGFicyh0aXRsZSA9ICJXaGF0IGZsYXZvcnMgYXBwZWFyIHRvIGJlIHVzZWQgdGhlIG1vc3QgZnJlcXVlbnRseT8iLAogICAgc3VidGl0bGUgPSAiRmxhdm9ycyBvZiB0b2JhY2NvIHByb2R1Y3RzIHVzZWQgaW4gdGhlIHBhc3QgMzAgZGF5cyIpCgpwbG90NApgYGAKCkZyb20gdGhpcyBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgZnJ1aXQgZmxhdm9ycyBhcmUgdGhlIG1vc3Qgd2lkZWx5IHVzZWQgcHJvZHVjdHMsIGZvbGxvd2VkIGJ5IG1lbnRob2wgb3IgbWludCBmbGF2b3JlZCBwcm9kdWN0cy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlcmUgd2FzIGEgZ2VuZXJhbCBpbmNyZWFzZSBpbiB0aGUgdXNhZ2Ugb2YgZmxhdm9yZWQgcHJvZHVjdHMgb3ZlciB0aW1lLgoKV2Ugd2lsbCBub3cgbG9vayBzcGVjaWZpY2FsbHkgYXQgdGhlIHVzYWdlIG9mIGZsYXZvcmVkIGUtY2lnYXJldHRlIHByb2R1Y3RzIHZzIG90aGVyIGZsYXZvcmVkIHRvYmFjY28gcHJvZHVjdHMuIAoKUmVjYWxsIHRoYXQgd2UgbWFkZSBhIHZhcmlhYmxlIGNhbGxlZCBgR3JvdXBgIHRoYXQgaWRlbnRpZmllZCBzdHVkZW50cyB3aG8gdXNlZCBlaXRoZXIganVzdCBlLWNpZ2FyZXR0ZS92YXBpbmcgcHJvZHVjdHMsIGp1c3Qgb3RoZXIgdG9iYWNjbyBwcm9kdWN0cyAoYmVzaWRlcyBlLWNpZ2FyZXR0ZXMpLCBvciBzdHVkZW50cyB3aG8gdXNlZCBib3RoIGUtY2lnYXJldHRlcyBhbmQgc29tZSBvdGhlciB0eXBlIG9mIHRvYmFjY28gcHJvZHVjdC4gV2Ugd2lsbCBjb21wYXJlIHRoZSB1c2FnZSBvZiB0aGVzZSBmbGF2b3JzIGZvciB0aGVzZSBkaWZmZXJlbnQgZ3JvdXBzLiBXZSBhbHNvIHBlcmZvcm0gc29tZSBkYXRhIHN1bW1hcmllcyB0byBkZWNpZGUgaG93IHRvIG9yZGVyIHRoZSBwYW5lbHMgKGZsYXZvcnMpIGZvciBkaXNwbGF5LgoKCgpgYGB7cn0KCnZfY29sb3JzID0gIHZpcmlkaXMoNSlbMTo0XQoKcGxvdDUgPC0gbnl0c19kYXRhICU+JQogIGZpbHRlcih5ZWFyICE9IDIwMTUpICU+JQogIGdyb3VwX2J5KHllYXIsIEdyb3VwKSAlPiUKICAgICAgICBzdW1tYXJpemUoTWVudGhvbCA9IChtZWFuKG1lbnRob2wpICogMTAwKSwKICAgICAgICAgYENsb3ZlIG9yIFNwaWNlYCA9IChtZWFuKGNsb3ZlX3NwaWNlKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgRnJ1aXQgPSAobWVhbihmcnVpdCkgKiAxMDApLAogICAgICAgICAgICAgICAgQ2hvY29sYXRlID0gKG1lYW4oY2hvY29sYXRlKSAqIDEwMCksCiAgICAgICAgYEFsY29ob2xpYyBEcmlua2AgPSAobWVhbihhbGNvaG9saWNfZHJpbmspICogMTAwKSwKICBgQ2FuZHkvRGVzc2VydHMvXG5Td2VldHNgID0gKG1lYW4oY2FuZHlfZGVzc2VydF9zd2VldHMpICogMTAwKSwKICAgICAgICAgICAgICAgICAgICBPdGhlciA9IChtZWFuKG90aGVyKSAqIDEwMCksCiAgICAgICAgICAgICAgUmVzcG9uZGVudHMgPSBuKCkpICU+JQogICMgY29udmVydGluZyBjb2x1bW5zIGJldHdlZW4gYW5kIGluY2x1ZGluZyBNZW50aG9sIGFuZCBPdGhlciB0byBvbmUgY29sdW1uIGNhbGxlZCBGbGF2b3IKICBwaXZvdF9sb25nZXIoY29scyA9IE1lbnRob2w6T3RoZXIsIAogICAgICAgICAgIG5hbWVzX3RvID0gIkZsYXZvciIsIAogICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBncm91cF9ieShGbGF2b3IpICU+JQogICMgY2FsY3VsYXRlIHRoZSBjb3VudCBvZiBzdHVkZW50cyBpbiB0aGUgeWVhci9ncm91cCBjb21iaW5hdGlvbiB3aG8gdXNlZCB0aGF0IGZsYXZvcgogIG11dGF0ZShhZmZpcm1hdGl2ZSA9IChSZXNwb25kZW50cyAqIGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCkgLyAxMDApICU+JQogICMgY2FsY3VsYXRlIHRoZSBmcmFjdGlvbiBvZiB0b3RhbCByZXNwb25kZW50cyB3aG8gdXNlZCB0aGF0IGZsYXZvcgogIG11dGF0ZShmbGF2b3JfbWVhbiA9IHN1bShhZmZpcm1hdGl2ZSkgLyBzdW0oUmVzcG9uZGVudHMpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyByZW9yZGVyIHRoZSBsZXZlbHMgb2YgRmxhdm9yIHRvIGJlIGluIGluY3JlYXNpbmcgb3JkZXIgb2YgcGVyY2VudCBvZiBzdHVkZW50cwogIG11dGF0ZShmbGF2b3JfbWVhbl9yYW5rID0gZGVuc2VfcmFuayhmbGF2b3JfbWVhbiksCiAgICAgICAgIEZsYXZvciA9IGZjdF9yZW9yZGVyKEZsYXZvciwgZmxhdm9yX21lYW5fcmFuaykpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIAogICAgICAgICAgICAgeSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgCiAgICAgICAgIGNvbG9yID0gR3JvdXApKSArCiAgZmFjZXRfZ3JpZCh+Rmxhdm9yKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSwgc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwKICAgICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpKSArCiAgbGFicyh0aXRsZSA9ICJBbW9uZyBkaWZmZXJlbnQgcHJvZHVjdCB1c2Vycywgd2hhdCBmbGF2b3JzIGFyZSBtb3N0IGZyZXF1ZW50bHkgdXNlZD8iKQoKcGxvdDUKYGBgCgoKV2UgY2FuIHNlZSBmcm9tIHRoaXMgcGxvdCB0aGF0IHRoZXJlIGhhcyBiZWVuIGFuIGluY3JlYXNlIGluIHRoZSBudW1iZXIgb2Ygc3R1ZGVudHMgcmVwb3J0aW5nIHVzaW5nIGZsYXZvcmVkIHRvYmFjY28gcHJvZHVjdHMuIFVzZXJzIHdobyB1c2UgYm90aCBlLWNpZ2FyZXR0ZXMgYW5kIG90aGVyIHRvYmFjY28gcHJvZHVjdHMgYXBwZWFyIHRvIHJlcG9ydCB1c2luZyBmbGF2b3JlZCBwcm9kdWN0cyB0aGUgbW9zdCwgZm9sbG93ZWQgYnkgdXNlcnMgd2hvIG9ubHkgdXNlIGUtY2lnYXJldHRlcy4KCiMjIyAqKlF1ZXN0aW9uIDQqKgoqKioKCklzIHRoZXJlIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gZS1jaWdhcmV0dGUgdXNlIGFuZCB0b2JhY2NvIHVzZT8gTm93IHdlIHdpbGwgaW52ZXN0aWdhdGUgdGhlIHVzYWdlIG9mIGUtY2lnYXJldHRlcyBjb21wYXJlZCB0byBvdGhlciB0b2JhY2NvIHByb2R1Y3RzIGluIGdyZWF0ZXIgZGVwdGguIAoKRmlyc3QgbGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IGUtY2lnYXJldHRlIHVzYWdlIGFuZCBjaWdhcmV0dGUgdXNhZ2UgY29tcGFyZS4gV2Ugd2lsbCBzZWxlY3QgdGhlIGRhdGEgdGhhdCBzcGVjaWZpY2FsbHkgaGFzIHRvIGRvIHdpdGggdGhlc2UgcHJvZHVjdHMuCgpgYGB7cn0KCgp2X2NvbG9ycyA9ICB2aXJpZGlzKDYpW2MoMSwgNCldCgpueXRzX2RhdGEgJT4lCiAgICBncm91cF9ieSh5ZWFyKSAlPiUKICAgIHN1bW1hcml6ZSgiQ2lnYXJldHRlcywgRXZlciIgPSAobWVhbihFQ0lHVCwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICJFLWNpZ2FyZXR0ZXMsIEV2ZXIiID0gKG1lYW4oRUVMQ0lHVCwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgIkNpZ2FyZXR0ZXMsIEN1cnJlbnQiID0gKG1lYW4oQ0NJR1QsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAiRS1jaWdhcmV0dGVzLCBDdXJyZW50IiA9IChtZWFuKENFTENJR1QsIG5hLnJtID0gVFJVRSkgKiAxMDApKSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gLSB5ZWFyLCAKICAgICAgICAgICAgIG5hbWVzX3RvID0gIkNhdGVnb3J5IiwgCiAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50YWdlIG9mIHN0dWRlbnRzIikgJT4lCiAgICBzZXBhcmF0ZShDYXRlZ29yeSwgaW50byA9IGMoIlByb2R1Y3QiLCAiVXNlciIpLCBzZXAgPSAiLCAiKSAlPiUKICAgIGhlYWQoKQoKCnBsb3Q2IDwtIG55dHNfZGF0YSAlPiUKICAgIGdyb3VwX2J5KHllYXIpICU+JQogICAgc3VtbWFyaXplKCJDaWdhcmV0dGVzLCBFdmVyIiA9IChtZWFuKEVDSUdULCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgIkUtY2lnYXJldHRlcywgRXZlciIgPSAobWVhbihFRUxDSUdULCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAiQ2lnYXJldHRlcywgQ3VycmVudCIgPSAobWVhbihDQ0lHVCwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICJFLWNpZ2FyZXR0ZXMsIEN1cnJlbnQiID0gKG1lYW4oQ0VMQ0lHVCwgbmEucm0gPSBUUlVFKSAqIDEwMCkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtIHllYXIsIAogICAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLCAKICAgICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICAgIHNlcGFyYXRlKENhdGVnb3J5LCBpbnRvID0gYygiUHJvZHVjdCIsICJVc2VyIiksIHNlcCA9ICIsICIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0geWVhciwgCiAgICAgICAgICAgICAgIHkgPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2AsIAogICAgICAgICAgIGNvbG9yID0gUHJvZHVjdCwKICAgICAgICBsaW5ldHlwZSA9IFVzZXIpKSArCiAgICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBkb2VzIGUtY2lnYXJldHRlIHVzZSBjb21wYXJlIHRvIGNpZ2FyZXR0ZSB1c2U/IiwKICAgICAgc3VidGl0bGUgPSAiQ3VycmVudCBhbmQgZXZlciB1c2VycyBvZiBlLWNpZ2FyZXR0ZXMgYW5kIGNpZ2FyZXR0ZXMiLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKcGxvdDYKYGBgCgpJbnRlcmVzdGluZyEgd2UgY2FuIHNlZSB0aGF0IGluIDIwMTkgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMgdGhhdCByZXBvcnRlZCBjdXJyZW50bHkgdXNpbmcgZS1jaWdhcmV0dGVzIGhhZCBzdXJwYXNzZWQgdGhvc2UgdGhhdCBldmVyIHRyaWVkIChldmVuIGp1c3Qgb25jZSkgYSBjaWdhcmV0dGUuIE92ZXJhbGwgY2lnYXJldHRlIHVzYWdlIGFwcGVhcnMgdG8gYmUgZGVjbGluaW5nIG92ZXIgdGltZS4gVGhpcyBpcyBub3QgdGhlIGNhc2UgZm9yIGUtY2lnYXJldHRlcy4KCgpOb3cgd2Ugd2lsbCBsb29rIGF0IHN0dWRlbnRzIHdobyByZXBvcnRlZCB0aGF0IHRoZXkgaGFkIGV2ZXIgdHJpZWQgZS1jaWdhcmV0dGVzIG9yIG5vbi1jaWdhcmV0dGUgcHJvZHVjdHMuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIG5vdCBzZXBhcmF0ZSBvdXQgdXNlcnMgd2hvIHNwZWNpZmljYWxseSBvbmx5IHVzZWQgb25lIG9yIHRoZSBvdGhlci4gVGhlcmVmb3JlLCB0aGUgc3R1ZGVudHMgaW5jbHVkZWQgaW4gdGhpcyBwbG90IHdobyByZXBvcnRlZCBhcyBoYXZpbmcgZXZlciB0cmllZCBlLWNpZ2FyZXR0ZXMgbWlnaHQgYWxzbyBiZSAgY3VycmVudCB1c2VycyBvZiBub24tZS1jaWdhcmV0dGUgcHJvZHVjdHMgb3IgbWF5IGhhdmUgYXQgbGVhc3QgdHJpZWQgbm9uLWUtY2lnYXJldHRlIHByb2R1Y3RzLgoKCmBgYHtyfQoKdl9jb2xvcnMgPSAgdmlyaWRpcyg2KVtjKDEsIDQpXQoKcGxvdDcgPC0gbnl0c19kYXRhICU+JQogICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgIHN1bW1hcml6ZShgZS1jaWdhcmV0dGVfZXZlcmAgPSAobWVhbihlY2lnX2V2ZXIsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAgICBgbm9uLWUtY2lnYXJldHRlX2V2ZXJgID0gKG1lYW4obm9uX2VjaWdfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtIHllYXIsIAogICAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLCAKICAgICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICAgIHNlcGFyYXRlKENhdGVnb3J5LCBpbnRvID0gYygiUHJvZHVjdCIsICJVc2VyIiksIHNlcCA9ICJfIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCAKICAgICAgICAgICAgICAgeSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgCiAgICAgICAgICAgY29sb3IgPSBQcm9kdWN0KSkgKwogICAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSwgc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDYwLCBieSA9IDEwKSwgbGltaXRzID0gYygwLCA2MCkpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiSG93IGRvZXMgdGhlIHJhdGUgb2YgZXZlciB0cnlpbmcgZS1jaWdhcmV0dGVzIApjb21wYXJlIHRvIGV2ZXIgdHJ5aW5nIG90aGVyIHByb2R1Y3RzIG92ZXIgdGltZT8iLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKcGxvdDcKYGBgCgoKTm93IHdlIHdpbGwgZG8gdGhlIHNhbWUsIGJ1dCBmb3Igc3R1ZGVudHMgd2hvIHJlcG9ydGVkIGN1cnJlbnRseSB1c2luZyBlLWNpZ2FyZXR0ZXMgb3Igbm9uLWUtY2lnYXJldHRlIHByb2R1Y3RzLiAKCgpgYGB7cn0Kdl9jb2xvcnMgPSAgdmlyaWRpcyg2KVtjKDEsIDQpXQoKcGxvdDggPC0gbnl0c19kYXRhICU+JQogICAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgIHN1bW1hcml6ZShgZS1jaWdhcmV0dGVfY3VycmVudGAgPSAobWVhbihlY2lnX2N1cnJlbnQsIG5hLnJtID0gVFJVRSkgKiAxMDApLAogICAgICAgICAgICBgbm9uLWUtY2lnYXJldHRlX2N1cnJlbnRgID0gKG1lYW4obm9uX2VjaWdfY3VycmVudCwgbmEucm0gPSBUUlVFKSAqIDEwMCkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtIHllYXIsIAogICAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLAogICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogICAgc2VwYXJhdGUoQ2F0ZWdvcnksIGludG8gPSBjKCJQcm9kdWN0IiwgIlVzZXIiKSwgc2VwID0gIl8iKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2AsIGNvbG9yID0gUHJvZHVjdCkpICsKICAgIGdlb21fbGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMCwgNjApKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIkhvdyBkb2VzIHRoZSByYXRlIG9mIGN1cnJlbnRseSB1c2luZyBlLWNpZ2FyZXR0ZXMKY29tcGFyZSB0byBjdXJyZW50bHkgdXNpbmcgb3RoZXIgcHJvZHVjdHMgb3ZlciB0aW1lPyIsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90OApgYGAKCiMjIyAqKlB1dHRpbmcgcGxvdHMgdG9nZXRoZXIqKgoqKioKCk5vdyB3ZSB3aWxsIHB1dCB0aGVzZSBwbG90cyB0b2dldGhlciB1c2luZyB0aGUgYHBsb3RfZ3JpZCgpYCBmdW5jdGlvbiBvZiB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UuICBXZSB3aWxsIGFsc28gbW9kaWZ5IHRoZSBsYWJlbHMgdXNpbmcgdGhlIGBnZ2RyYXcoKWAgZnVuY3Rpb24sIHdoaWNoIGlzIGFsc28gcGFydCBvZiB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UuCgpgYGB7ciwgZmlnLmhlaWdodD0xMH0KcGxvdEFfdXcgPC0gcGxvdDEgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIGxhYnModGl0bGUgPSAiVG9iYWNjbyBwcm9kdWN0IHVzZXJzIG1vcmUgcHJldmFsZW50IGFmdGVyIDIwMTciLAogICAgICAgICBzdWJ0aXRsZSA9IE5VTEwsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgpwbG90Ql91dyA8LSBwbG90NyArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICIlIEV2ZXIgdHJ5aW5nIGUtY2lnYXJldHRlcyBpbmNyZWFzZXMgJgolIEV2ZXIgdHJ5aW5nIG90aGVyIHByb2R1Y3RzIGRlY3JlYXNlcyIsCiAgICAgICAgIHN1YnRpdGxlID0gTlVMTCwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RDX3V3IDwtIHBsb3Q4ICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBsYWJzKHRpdGxlID0gIiUgQ3VycmVudGx5IHVzaW5nIGUtY2lnYXJldHRlcyBpbmNyZWFzZXMgJgolIEN1cnJlbnRseSB1c2luZyBvdGhlciBwcm9kdWN0cyBkZWNyZWFzZXMiLAogICAgICAgICBzdWJ0aXRsZSA9IE5VTEwsCiAgICAgICAgIHkgPSAiJSBvZiBzdHVkZW50cyIpCgp0aXRsZV91dyA8LSBnZ2RyYXcoKSArCiAgZHJhd19sYWJlbCgKICAgICJJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGUtY2lnYXJldHRlIHVzZSBhbmQgdG9iYWNjbyB1c2U/IiwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgc2l6ZSA9IDE0LAogICAgeCA9IDAsCiAgICBoanVzdCA9IDAKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdHNBX3V3IDwtIHBsb3RfZ3JpZChwbG90QV91dywKICAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSwgMSkpCnBsb3RzQkNfdXcgPC0gcGxvdF9ncmlkKHBsb3RCX3V3LAogICAgICAgICAgICAgICAgICAgICAgICBwbG90Q191dywKICAgICAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSwgMSkpCgojIHRoaXMgd2lsbCB0YWtlIHRoZSBsZWdlbmQgZnJvbSBwbG90MWMgdG8gdXNlIGFzIHRoZSBsZWdlbmQgZm9yIHRoZSBwbG90IHdlIGFyZSBjcmVhdGluZwpsZWdlbmRfdXcgPC0gZ2V0X2xlZ2VuZChwbG90MWMgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKZmlndXJlX3V3IDwtIHBsb3RfZ3JpZCh0aXRsZV91dywKICAgICAgICAgICAgICAgICAgICAgICBwbG90c0FfdXcsCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdHNCQ191dywKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfdXcsCiAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4xKSwKICAgICAgICAgICAgICAgICAgICAgICBzY2FsZSA9IDEuMCkKCmZpZ3VyZV91dwpgYGAKCgojIyMgKipTdXJ2ZXkgV2VpZ2h0aW5nKioqCioqKgpgYGB7ciwgZWNobyA9IEZBTFNFfQojSWYgaW5zdHJ1Y3RvcnMgc3RhcnQgaGVyZSwgd2UgbmVlZCB0byBsb2FkIHRoZSBkYXRhOgpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWRfZGF0YV93aXRoX3Zhcl9mb3JfcGxvdHMucmRhIikpCmBgYAogIApJdCB0dXJucyBvdXQgdGhhdCBvdXIgYW5hbHlzaXMgdGh1cyBmYXIgaGFzIGJlZW4gYnJ1c2hpbmcgYW4gaW1wb3J0YW50IHN0YXRpc3RpY2FsIGNvbmNlcHQgdW5kZXIgdGhlIHJ1ZywgcmVsYXRlZCB0byBob3cgb3VyIGRhdGEgd2VyZSBjb2xsZWN0ZWQuIE91ciBkYXRhIGNvbWUgZnJvbSByZXNwb25zZXMgdG8gYSBzdXJ2ZXksIHdoaWNoIG1heSBoYXZlIGEgcGFydGljdWxhciBzYW1wbGluZyBzY2hlbWUgdG8gY2FwdHVyZSBkYXRhIGFib3V0IHRoZSBwb3B1bGF0aW9uIHdlIGFyZSBpbnRlcmVzdGVkIGluLiBGb3IgZXhhbXBsZSwgdGhlIHN1cnZleSBtYXkgYmUgZGVzaWduZWQgdG8gY2FwdHVyZSBhIHNldCBvZiBpbmRpdmlkdWFscyB3aG8gcmVmbGVjdCB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gZHJhd2luZyBjb25jbHVzaW9ucyBhYm91dC4gSG93ZXZlciwgb25seSBhIGZyYWN0aW9uIG9mIHRoZSBpbmRpdmlkdWFscyB3aG8gd2VyZSBjb250YWN0ZWQgYWJvdXQgdGFraW5nIHRoZSBzdXJ2ZXkgbWF5IGhhdmUgY29tcGxldGVkIGl0LCBhbmQgdGhpcyBmcmFjdGlvbiBvZiBpbmRpdmlkdWFscyBtYXkgbm8gbG9uZ2VyIGJlIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBwb3B1bGF0aW9uLiBPciB0aGUgc3VydmV5IG1heSBiZSBkZXNpZ25lZCB0byBvdmVyLXNhbXBsZSBhIHBhcnRpY3VsYXIgZ3JvdXAgb2YgaW50ZXJlc3Qgc28gdGhhdCBpbmRpdmlkdWFscyBmcm9tIHRoYXQgZ3JvdXAgc2hvdyB1cCBtb3JlIG9mdGVuIGFzIHN1cnZleSByZXNwb25kZW50cyB0aGFuIGFyZSBwcmVzZW50IGluIHRoZSBwb3B1bGF0aW9uIG92ZXJhbGwuIEluIG9yZGVyIHRvIGFjY291bnQgZm9yIHRoZSBmYWN0IHRoYXQgdGhlIHN1cnZleSByZXNwb25kZW50cyBtYXkgbm90IHJlZmxlY3QgdGhlIGNvbXBvc2l0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIHdlIHdhbnQgdG8gZ2VuZXJhbGl6ZSB0bywgd2UgY2FuIGVtcGxveSBhIHRlY2huaXF1ZSBjYWxsZWQgW3N1cnZleSB3ZWlnaHRpbmddKGh0dHA6Ly93d3cuYXBwbGllZC1zdXJ2ZXktbWV0aG9kcy5jb20vd2VpZ2h0Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgpTdXJ2ZXkgd2VpZ2h0aW5nIGlzIGEgY29tbW9uIHRlY2huaXF1ZSB1c2VkIGluIHN1cnZleSBkYXRhIGFuYWx5c2lzIGJlY2F1c2Ugb2Z0ZW4gdGhlIGluZGl2aWR1YWxzIHRoYXQgdGFrZSBhIHN1cnZleSBhcmUgbm90IG5lY2Vzc2FyaWx5IHJlcHJlc2VudGF0aXZlIG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgd2UgYXJlIHRyeWluZyB0byBnYXRoZXIgaW5mb3JtYXRpb24gYWJvdXQuIEZvciBleGFtcGxlLCB3ZSBtYXkgaGF2ZSBtb3JlIGZlbWFsZXMgdGhhdCByZXNwb25kIHRvIHRoZSBzdXJ2ZXkgdGhhbiBtYWxlcyBiZWNhdXNlIHBlcmhhcHMgZmVtYWxlIHN0dWRlbnRzIHdlcmUgbW9yZSB3aWxsaW5nIHRvIHBhcnRpY2lwYXRlLiBJbiB0aGlzIGNhc2UsIHRoZSBwcm9wb3J0aW9uIG9mIGRhdGEgdmFsdWVzIGluIG91ciBkYXRhIHdpbGwgYmUgc21hbGxlciBmb3IgdGhlIG1hbGVzIHRoYW4gdGhlIHByb3BvcnRpb24gb2YgYWN0dWFsIG1hbGUgc3R1ZGVudHMgYW5kIGxhcmdlciBmb3IgdGhlIGZlbWFsZXMgdGhhbiB0aGUgdHJ1ZSBwcm9wb3J0aW9uIG9mIGFjdHVhbCBmZW1hbGUgc3R1ZGVudHMuIFRvIGdldCBhIGJldHRlciBlc3RpbWF0ZSBvZiBvdmVyYWxsIGUtY2lnYXJldHRlIHNtb2tpbmcgcmF0ZXMsIHRoZSBkYXRhIGZyb20gdGhlIG1hbGVzIGNhbiBiZSB3ZWlnaHRlZCBiYXNlZCBvbiB0aGUgdHJ1ZSBwcm9wb3J0aW9uIG9mIG1hbGUgc3R1ZGVudHMgdG8gYW1wbGlmeSB0aGUgY29udHJpYnV0aW9uIG9mIHRoZSByZXNwb25zZXMgZnJvbSB0aGUgbWFsZXMgdGhhdCBkaWQgcGFydGljaXBhdGUuIENvbnZlcnNlbHksIHRoZSBmZW1hbGUgZGF0YSBjYW4gYmUgd2VpZ2h0ZWQgdG8gZGltaW5pc2ggdGhlIGNvbnRyaWJ1dGlvbiBpZiB0aGVpciByZXNwb25zZXMgdG8gdGhlIG92ZXJhbGwgcGljdHVyZS4gV2Ugd2lsbCBzZWUgaWYgdXNpbmcgc3VydmV5IHdlaWdodGluZyBjaGFuZ2VzIHRoZSBnZW5lcmFsIHRyZW5kcyB0aGF0IHdlIHNlZSBpbiBvdXIgZGF0YS4gCgpDYWxjdWxhdGluZyBzdXJ2ZXkgd2VpZ2h0cyBpbnZvbHZlcyBtYWtpbmcgYSB3ZWlnaHQgYmFzZWQgb24gdGhlIHJhdGlvIG9mIHRoZSBwcm9wb3J0aW9uIG9mIHN1cnZleSByZXNwb25kZW50cyBmcm9tIGEgcGFydGljdWxhciBncm91cCBhbmQgdGhlIGFjdHVhbCBwcm9wb3J0aW9uIG9mIHRoYXQgZ3JvdXAgaW4gdGhlIHBvcHVsYXRpb24uIEZvciBleGFtcGxlLCBsZXQncyBzYXkgdGhhdCBmZW1hbGVzIGFjY291bnQgZm9yIDUwJSBvZiB0aGUgcG9wdWxhdGlvbiBhbmQgbWFsZXMgYWNjb3VudCBmb3IgNTAgJSBvZiB0aGUgcG9wdWxhdGlvbi4gTGV0J3MgYWxzbyBzYXkgdGhhdCA3NSUgb2YgdGhlIHJlc3BvbmRlbnRzIHRvIHRoZSBzdXJ2ZXkgd2VyZSBmZW1hbGUgYW5kIG9ubHkgMjUlIHdlcmUgbWFsZXMuIAoKVGhlbiB3ZSBjb3VsZCBjYWxjdWxhdGUgc3VydmV5IHdlaWdodHMgdXNpbmcgdGhpcyBmb3JtdWxhOgoKJCQgXGZyYWN7XHRleHR7YWN0dWFsIHByb3BvcnRpb24gb2YgZ3JvdXAgaW4gdGhlIHBvcHVsYXRpb259fXtcdGV4dHsgcHJvcG9ydGlvbiBvZiBncm91cCBpbiB0aGUgcmVzcG9uZGVudHN9fSQkICAKClRodXMgdGhlIHdlaWdodCBmb3IgdGhlIGZlbWFsZXMgd291bGQgYmUgY2FsY3VsYXRlZCBhczoKCiQkIFxmcmFjey41fXsuNzV9ID0gLjY3JCQgIAoKVGhlIHdlaWdodCBmb3IgdGhlIG1hbGVzIHdvdWxkIGJlIGNhbGN1bGF0ZWQgYXM6CgokJCBcZnJhY3suNX17LjI1fSA9IDIkJAoKVGhlcmVmb3JlIGVhY2ggbWFsZSByZXNwb25zZSB2YWx1ZSB3b3VsZCBiZSBtdWx0aXBsaWVkIGJ5IGEgZmFjdG9yIG9mIDIgYW5kIHdvdWxkIGhhdmUgdHdpY2UgdGhlIGNvbnRyaWJ1dGlvbiwgd2hpbGUgdGhlIGZlbWFsZSByZXNwb25zZSB2YWx1ZXMgd291bGQgaGF2ZSBvbmx5IGFib3V0IDcwJSBvZiB0aGUgY29udHJpYnV0aW9uIHRoYXQgdGhleSB3b3VsZCBoYXZlIGhhZCB3aXRob3V0IHdlaWdodGluZy4KCk5vdGUgdGhhdCBzdXJ2ZXkgd2VpZ2h0cyBhcmUgaW4gcmVhbGl0eSBjb3JyZWN0ZWQgZm9yIG90aGVyIGFzcGVjdHMgLSBmb3IgZXhhbXBsZSB0aGUgcmVzcG9uc2UgcmF0ZSB0byBpbmRpdmlkdWFsIHF1ZXN0aW9ucy4KCldlIGRvIG5vdCBuZWVkIHRvIGNhbGN1bGF0ZSBzdXJ2ZXkgd2VpZ2h0cyBmb3Igb3VyIGRhdGEgYXMgdGhleSB3ZXJlIGFscmVhZHkgc3VwcGxpZWQgaW4gdGhlIGRhdGEgc2V0LCBhcyBkZXNjcmliZWQgaW4gdGhlIGNvZGVib29rcy4gCgojIyMjIGBzcnZ5cmAgcGFja2FnZSBhbmQgc3VydmV5IGRlc2lnbiAKCioqKgoKV2Ugd2lsbCBub3cgdXNlIHRoZSBgc3J2eXJgIHBhY2thZ2UgdG8gZXZhbHVhdGUgb3VyIGRhdGEgdXNpbmcgc3VydmV5IHdlaWdodHMgdGhhdCB3ZXJlIHByb3ZpZGVkIGluIHRoZSBkYXRhIGZvciBlYWNoIHllYXIsIGFzIGRlc2NyaWJlZCBpbiB0aGUgcmVzcGVjdGl2ZSBjb2RlYm9va3MuIFRoaXMgcGFja2FnZSBjb250YWlucyBmdW5jdGlvbnMgdGhhdCBhbGxvdyB0aGUgdXNlciB0byBlYXNpbHkgcGVyZm9ybSBjYWxjdWxhdGlvbnMgZnJvbSB0aGUgZGF0YSB0aGF0IHRha2UgdGhlIHN1cnZleSBkZXNpZ24gaW50byBhY2NvdW50LCB3aXRob3V0IGhhdmluZyB0byB3b3JrIG91dCB0aGUgbWF0aCBieSBoYW5kLgoKV2l0aGluIHRoZSBkYXRhIHlvdSB3aWxsIHNlZSB0aGF0IHdlIGhhdmUgdGhyZWUgdmFyaWFibGVzIHJlbGF0ZWQgdG8gdGhlIHN1cnZleSBzYW1wbGluZyBzY2hlbWU6ICBgcHN1YCwgYGZpbndndGAsIGFuZCBgc3RyYXR1bWAuIERldGFpbHMgYWJvdXQgdGhlc2UgdmFyaWFibGVzIGFyZSBhdmFpbGFibGUsIGZvciBleGFtcGxlLCBpbiB0aGUgWzIwMTkgTWV0aG9kb2xvZ3kgUmVwb3J0XSguL2RvY3MvMjAxOS1ueXRzLWRhdGFzZXQtYW5kLWNvZGVib29rLW1pY3Jvc29mdC1leGNlbC8yMDE5LW55dHMtbWV0aG9kb2xvZ3ktcmVwb3J0LXAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9LgoKSW4gYnJpZWYgdGhleSByZXByZXNlbnQ6IAoKMSkgYHBzdWA6IFN1cnZleXMgbGlrZSB0aGUgb25lIHVzZWQgdG8gY3JlYXRlIHRoZSBkYXRhIHdlIGFyZSB1c2luZyBvZnRlbiBzYW1wbGUgcGVvcGxlIGJhc2VkIG9uIHN0cmF0YS4gVGhpcyBpcyBkb25lIHRvIGVuc3VyZSB0aGF0IHRoZSByZXNwb25zZXMgYXJlIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0LiBUaHVzLCBvZnRlbiBwZW9wbGUgZmlyc3QgdGhpbmsgYWJvdXQgZW5zdXJpbmcgdGhhdCBzdXJ2ZXlzIGFyZSBjb25kdWN0ZWQgaW4gYSB2YXJpZXR5IG9mIGdlb2dyYXBoaWNhbCBhcmVhcy4gVGhpcyBpcyBvZnRlbiBjYWxsZWQgdGhlICoqcHJpbWFyeSBzYW1wbGluZyB1bml0Kiogb3IgKipQU1UqKi4gSW4gW3RoaXMgc3VydmV5XShodHRwczovL3dlYi5zcGguaGFydmFyZC5lZHUvbWNoLWRhdGEtY29ubmVjdC9yZXN1bHRzL25hdGlvbmFsLXlvdXRoLXRvYmFjY28tc3VydmV5LW55dHMvKXt0YXJnZXQ9Il9ibGFuayJ9LCB0aGUgY291bnR5IHdoZXJlIHRoZSBzdHVkZW50J3Mgc2Nob29sIHdhcyBsb2NhdGVkIHdhcyB1c2VkIGFzIHRoZSBQU1UuIAoKMikgYHN0cmF0dW1gOiBBIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHRoYXQgaW5kaWNhdGVzIHN1YnNldHMgb2YgdGhlIGRhdGEgdGhhdCBpbmNsdWRlIHJlc3BvbmRlbnRzIGZyb20gZGlmZmVyZW50ICpQU1VzKi4gSW4gb3VyIGNhc2UsIHN0cmF0YSBhcmUgZGV0ZXJtaW5lZCBieSB0aGUgcHJlZG9taW5hbnQgbWlub3JpdHkgaW4gdGhlIFBTVSAoTm9uLUhpc3BhbmljIEJsYWNrIG9yIEhpc3BhbmljKSwgd2hldGhlciB0aGUgUFNVIGlzIHVyYmFuIG9yIG5vbi11cmJhbiwgYW5kIHdoYXQgcGVyY2VudCBvZiB0aGUgc3R1ZGVudHMgaW4gdGhlIFBTVSBmYWxsIGludG8gdGhlIHByZWRvbWluYW50IG1pbm9yaXR5IGdyb3VwLiBQU1VzIGFyZSBhbGxvY2F0ZWQgYWNyb3NzIHRoZSAxNiBwb3NzaWJsZSBzdHJhdGEgYWNjb3JkaW5nIHRvIHRoZSBzYW1wbGluZyBzY2hlbWUuIFRoZXNlIHN0cmF0YSB2YWx1ZXMgYWxsb3cgZXN0aW1hdGVzIGJhc2VkIG9uIHRoZSBzdXJ2ZXkgcmVzcG9uc2VzIHRvIGJlIGNhbGN1bGF0ZWQgdXNpbmcgZGlmZmVyZW50IHN0cmF0YSBhbGxvd2luZyBmb3IgaW1wcm92ZWQgcHJlY2lzaW9uIG9mIHRoZSByZXNwb25zZSBlc3RpbWF0ZXMuCgozKSBgZmlud2d0YDogVGhlIHN1cnZleSB3ZWlnaHQgd2hpY2ggd2FzIGNhbGN1bGF0ZWQgYmFzZWQgb24gYSB2YXJpZXR5IG9mIGZhY3RvcnMuCgpUaGlzIFtsaW5rXShodHRwczovL3dlYi5zcGguaGFydmFyZC5lZHUvbWNoLWRhdGEtY29ubmVjdC9yZXN1bHRzL25hdGlvbmFsLXlvdXRoLXRvYmFjY28tc3VydmV5LW55dHMvKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCB0aGlzIFtsaW5rXShodHRwczovL29zZi5pby9uN3IzMil7dGFyZ2V0PSJfYmxhbmsifSBoYXZlIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHN0dWR5IGRlc2lnbiBvZiB0aGUgZGF0YSB0aGF0IHdlIGFyZSB1c2luZy4KCkZvciBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiBzdWNoIHN1cnZleSBkZXNpZ25zIGluIGdlbmVyYWwgc2VlIFtoZXJlXShodHRwOi8vd3d3LmFzYXNybXMub3JnL1Byb2NlZWRpbmdzL3kyMDA4L0ZpbGVzLzMwMTgzNS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtoZXJlXShodHRwOi8vb2N3Lmpoc3BoLmVkdS9jb3Vyc2VzL1N0YXRNZXRob2RzRm9yU2FtcGxlU3VydmV5cy9QREZzL0xlY3R1cmU1LnBkZil7dGFyZ2V0PSJfYmxhbmsifS4KCldlIHdpbGwgdXNlIHRoZSBgYXNfc3VydmV5X2Rlc2lnbigpYCBmdW5jdGlvbiBvZiB0aGUgYHNydnlyYHBhY2thZ2UgdG8gY3JlYXRlIGEgc3VydmV5IG9iamVjdCB3aXRoIGEgc3BlY2lmaWVkIHN1cnZleSBkZXNpZ24uIFRoaXMgaXMgYSBzcGVjaWFsIFIgb2JqZWN0IHRoYXQgaW5jbHVkZXMgaW5mb3JtYXRpb24gYWJvdXQgaG93IHRoZSBzdXJ2ZXkgd2FzIGNvbmR1Y3RlZCB0aGF0IGNhbiBiZSB0YWtlbiBpbnRvIGFjY291bnQgaW4gdGhlIGFuYWx5c2lzLgoKVGhlcmUgYXJlIHNldmVyYWwgYXJndW1lbnRzIHRvIHBheSBhdHRlbnRpb24gdG86CgoxKSBUaGUgYHN0cmF0YWAgYXJndW1lbnQgaXMgdXNlZCB0byBzcGVjaWZ5IHRoZSB2YXJpYWJsZShzKSB0aGF0IGRlZmluZWQgc3RyYXRhIGluIHRoZSBkYXRhLiBJbiB0aGlzIGNhc2UsIHdlIHdpbGwgdXNlIHRoZSBgc3RyYXR1bWAgdmFyaWFibGUuCjIpIFRoZSBgaWRzYCBhcmd1bWVudCBpcyB1c2VkIHRvIGRlZmluZSBjbHVzdGVyIGlkcyB3aXRoaW4gdGhlIGRhdGEuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIHVzZSB0aGUgYHBzdWAgdmFyaWFibGUuCjMpIFRoZSBgd2VpZ2h0YCBhcmd1bWVudCBpcyB0aGUgIHVzZWQgdG8gZGVmaW5lIHdoaWNoIHZhcmlhYmxlKHMpIGFyZSB0aGUgc3VydmV5IHdlaWdodHMuCjQpIFRoZSBgbmVzdCA9IFRSVUVgIGFyZ3VtZW50LCBmb3JjZXMgY2x1c3RlciBpZHMgKGluIHRoaXMgY2FzZSB0aGUgUFNVKSB0byBiZSBuZXN0ZWQgd2l0aGluIHRoZSBzdHJhdGEuCgpXZSBjYW4gdGhlbiB1c2UgdGhlIGBzdXJ2ZXlfbWVhbigpYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgcGVyY2VudGFnZXMgb2Ygc3R1ZGVudHMgd2hvIHJlcG9ydCB1c2luZyB0b2JhY2NvIGZvciBlYWNoIHllYXIgd2hpbGUgYWNjb3VudGluZyBmb3IgdGhlIHN1cnZleSBkZXNpZ24gYW5kIHdlaWdodHMuIFdlIHdpbGwgc3BlY2lmeSB0aGF0IHdlIHdhbnQgW2NvbmZpZGVuY2UgaW50ZXJ2YWxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NvbmZpZGVuY2VfaW50ZXJ2YWwpe3RhcmdldD0iX2JsYW5rIn0gZXN0aW1hdGVzIGJ5IHVzaW5nIHRoZSBgdmFydHlwZSA9ICJjaSJgIGFyZ3VtZW50LiBUaGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgaW4gb3VyIGNhc2UgZ2l2ZSBhIHJhbmdlIG9mIHBvc3NpYmxlIHZhbHVlcyBmb3IgdGhlIHRydWUgcG9wdWxhdGlvbiBtZWFuIGJhc2VkIG9uIHRoZSBkYXRhIG9ic2VydmVkIGluIHRoZSBzdXJ2ZXkuIFdlIHdpbGwgbXVsdGlwbHkgdGhlc2UgdmFsdWVzIGJ5IDEwMCB0byBnZXQgcGVyY2VudGFnZXMuIChOb3RlOiBXZSBjb3VsZCBhbHNvIGhhdmUgY2FsY3VsYXRlZCBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIHVud2VpZ2h0ZWQgcmVzdWx0cyBhYm92ZSBieSBjb21wdXRpbmcgdGhlbSBieSBoYW5kOyB3ZSBsZWF2ZSB0aGlzIGFzIGEgcG90ZW50aWFsIGV4ZXJjaXNlLikKClNpbmNlIHRoZSBzdXJ2ZXkgd2VpZ2h0cyBhcmUgc3BlY2lmaWMgdG8gYSBzaW5nbGUgeWVhciBvZiB0aGUgc3VydmV5IHJlc3VsdHMsIHdlIG5lZWQgdG8gY3JlYXRlIHN1cnZleSBkZXNpZ24gb2JqZWN0cyBmb3IgZWFjaCB5ZWFyIHNlcGFyYXRlbHkuIFdlIHdpbGwgdXNlIGBncm91cF9ieWAgYW5kIGBncm91cF9tb2RpZnlgLCB3aGljaCBpcyBhbHNvIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZSwgdG8gZG8gdGhpcy4gV2UgZmlyc3Qgd3JpdGUgdGhlIGZ1bmN0aW9uIHRoYXQgd2Ugd2FudCB0byBjYWxsIG9uIGVhY2ggZ3JvdXAuCgpUaGlzIGZ1bmN0aW9uIHRha2VzIGFuIGlucHV0IGNhbGxlZCBgY3VyclllYXJgLCB3aGljaCB3aWxsIGJlIG9uZSBzZXQgb2Ygc3VydmV5IHJlc3BvbnNlcyBmb3IgYSBzcGVjaWZpYyB5ZWFyLCBhbmQgdGhlbiBjcmVhdGVzIGEgc3VydmV5IGRlc2lnbiBiYXNlZCBvbiB0aGUgYHN0cmF0dW1gIGFuZCBgZmlud2d0YCB2YWx1ZXMgc3BlY2lmaWMgdG8gdGhhdCB5ZWFyLiBJdCB0aGVuIGNhbGN1bGF0ZXMgdGhlIHBlcmNlbnQgb2Ygc3R1ZGVudCByZXNwb25kZW50cyB3aG8gaGF2ZSBldmVyIHRyaWVkIGFueSB0b2JhY2NvIHByb2R1Y3RzIG9yIHdobyBhcmUgYSBjdXJyZW50IHVzZXIgb2YgYW55IHRvYmFjY28gcHJvZHVjdHMgYWNjb3VudGluZyBmb3IgdGhlIHN1cnZleSBkZXNpZ24gYW5kIHdlaWdodHMgdXNpbmcgYHN1cnZleV9tZWFuKClgIGFzIHdhcyBqdXN0IGRlc2NyaWJlZC4gVGhlIGZ1bmN0aW9uIHRoZW4gd3JhbmdsZXMgdGhlIGRhdGEgdG8gY29udmVydCB0aGUgbWVhbnMgdG8gcGVyY2VudGFnZXMgYW5kIHJlZm9ybWF0IHRoZSBkYXRhIGluIGxvbmcgZm9ybSBmb3IgcGxvdHRpbmcuCgpPbmUgdGVjaG5pY2FsIG5vdGU6IHNpbmNlIHNvbWUgeWVhcnMgaGF2ZSBzdHJhdGEgd2l0aCBhIHNpbmdsZSBQU1UsIHdlIG5lZWQgdG8gdGVsbCB0aGUgc3VydmV5IHdlaWdodGluZyBwYWNrYWdlIGhvdyB0byBoYW5kbGUgZXN0aW1hdGluZyB3aXRoaW4gc3RyYXRhIHZhcmlhbmNlcy4gVGhlIGxpbmUgYG9wdGlvbnMoc3VydmV5LmxvbmVseS5wc3UgPSAiYWRqdXN0IilgIHRlbGxzIFIgdG8gY2VudGVyIHRoZSBzdHJhdHVtIHdpdGggdGhlIHNpbmdsZSBQU1Ugb24gdGhlIHNhbXBsZSBncmFuZCBtZWFuLCBhIGNvbnNlcnZhdGl2ZSBhcHByb2FjaCB0byBzb2x2aW5nIHRoZSBwcm9ibGVtLiBTZWUgZnVydGhlciBpbmZvcm1hdGlvbiBbaGVyZV0oaHR0cHM6Ly9yLXN1cnZleS5yLWZvcmdlLnItcHJvamVjdC5vcmcvc3VydmV5L2V4bWFtcGxlLWxvbmVseS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBbaGVyZV0oaHR0cDovL3Itc3VydmV5LnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9zdXJ2ZXkvaHRtbC9zdXJ2ZXlvcHRpb25zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgojIyMgKipXZWlnaHRlZCBTYW1wbGUqKgoqKioKCkZpcnN0LCB3ZSBzaG93IHRoZSBiYXNpYyBvdXRwdXQgb2YgdGhlIGBzdXJ2ZXlfbWVhbmAgZnVuY3Rpb24gYnkgeWVhci4gU2luY2Ugd2UgaW5jbHVkZSB0aGUgYXJndW1lbnQgYHZhcnR5cGUgPSAiY2kiYCwgd2UgZ2V0IGEgbWVhbiBhbmQgdXBwZXIgYW5kIGxvd2VyIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYm91bmRzIGZvciB0aGUgbWVhbi4KCmBgYHtyfQpzdXJ2ZXlNZWFuQSA8LSBmdW5jdGlvbihjdXJyWWVhcikgewogIG9wdGlvbnMoc3VydmV5LmxvbmVseS5wc3UgPSAiYWRqdXN0IikKICBjdXJyWWVhciAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sCiAgICAgICAgICAgICAgICAgICAgICBpZHMgPSBwc3UsCiAgICAgICAgICAgICAgICAgIHdlaWdodCAgPSBmaW53Z3QsCiAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKSAlPiUKICAgc3VtbWFyaXplKHRvYmFjY29fZXZlciA9IHN1cnZleV9tZWFuKHRvYmFjY29fZXZlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnR5cGUgPSAiY2kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwKICAgICAgICAgIHRvYmFjY29fY3VycmVudCA9IHN1cnZleV9tZWFuKHRvYmFjY29fY3VycmVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnR5cGUgPSAiY2kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkgfQoKCm55dHNfZGF0YSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBncm91cF9tb2RpZnkofiBzdXJ2ZXlNZWFuQSgueCkpICU+JQogIGhlYWQoKQpgYGAKCk5vdyBsZXQncyBtYWtlIHRoZSBmdW5jdGlvbiB3cmFuZ2xlIHRoZSBvdXRwdXQgaW4gYSBtb3JlIHVzYWJsZSBmb3JtIHRvbzoKYGBge3J9CgpzdXJ2ZXlNZWFuQSA8LSBmdW5jdGlvbihjdXJyWWVhcikgewogIG9wdGlvbnMoc3VydmV5LmxvbmVseS5wc3UgPSAiYWRqdXN0IikKICBjdXJyWWVhciAlPiUKICBhc19zdXJ2ZXlfZGVzaWduKHN0cmF0YSA9IHN0cmF0dW0sCiAgICAgICAgICAgICAgICAgICAgICBpZHMgPSBwc3UsCiAgICAgICAgICAgICAgICAgIHdlaWdodCAgPSBmaW53Z3QsCiAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKSAlPiUKICAgc3VtbWFyaXplKHRvYmFjY29fZXZlciA9IHN1cnZleV9tZWFuKHRvYmFjY29fZXZlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnR5cGUgPSAiY2kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwKICAgICAgICAgIHRvYmFjY29fY3VycmVudCA9IHN1cnZleV9tZWFuKHRvYmFjY29fY3VycmVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnR5cGUgPSAiY2kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkgICU+JQogIG11dGF0ZV9hbGwoIioiLCAxMDApICU+JQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiVHlwZSIsCiAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oc3RyX2RldGVjdChUeXBlLCAiX2xvdyIpIH4gIkxvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChUeXBlLCAiX3VwcCIpIH4gIlVwcGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSwKICAgICAgICAgVXNlciA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KFR5cGUsICJldmVyIikgfiAiRXZlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChUeXBlLCAiY3VycmVudCIpIH4gIkN1cnJlbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVhbiIpKX0KCm55dHNfZGF0YSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBncm91cF9tb2RpZnkofiBzdXJ2ZXlNZWFuQSgueCkpCmBgYAoKV2Ugd2lsbCBub3cgbWFrZSBhIHBsb3QgdXNpbmcgdGhpcyBkYXRhLiBUaGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIGluY2x1ZGVkIHVzaW5nIHRoZSBgZ2VvbV9saW5lcmFuZ2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLgoKYGBge3J9CnBsb3RBX3cgPC0gbnl0c19kYXRhICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+IHN1cnZleU1lYW5BKC54KSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtVHlwZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlLAogICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBNZWFuKSkgKwogIGdlb21fbGluZShhZXMobGluZXR5cGUgPSBVc2VyKSkgKwogIGdlb21fbGluZXJhbmdlKGFlcyh5bWluID0gTG93ZXIsCiAgICAgICAgICAgICAgICAgICAgIHltYXggPSBVcHBlciksIAogICAgICAgICAgICAgICAgICAgICBzaXplID0gMSwgCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA3MCwgYnkgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLCA3MCwgYnkgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgNzApKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICJUb2JhY2NvIHByb2R1Y3QgdXNlcnMgbW9yZSBwcmV2YWxlbnQgYWZ0ZXIgMjAxNyIsCiAgICAgICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQpwbG90QV93CmBgYAoKTm93IHdlIGNhbiBzZWUgdGhhdCB3ZSBoYXZlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgcmFuZ2VzIHBsb3R0ZWQgZm9yIGVhY2ggdmFsdWUuIAoKV2Ugd2lsbCBtYWtlIGEgc2ltaWxhciBwbG90IGZvciBzdHVkZW50cyB3aG8gcmVwb3J0ZWQgZXZlciB0cnlpbmcgb3Igd2hvIGN1cnJlbnRseSB1c2UgZS1jaWdhcmV0dGVzIGFzIG9wcG9zZWQgdG8gdG9iYWNjbyBpbiBnZW5lcmFsLgoKYGBge3J9CnZfY29sb3JzID0gIHZpcmlkaXMoNilbYygxLCA0KV0KCnN1cnZleU1lYW5CIDwtIGZ1bmN0aW9uKGN1cnJZZWFyKSB7CiAgb3B0aW9ucyhzdXJ2ZXkubG9uZWx5LnBzdSA9ICJhZGp1c3QiKQogIGN1cnJZZWFyICU+JQogIGFzX3N1cnZleV9kZXNpZ24oc3RyYXRhID0gc3RyYXR1bSwKICAgICAgICAgICAgICAgICAgICAgIGlkcyA9IHBzdSwKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwKICAgICAgICAgICAgICAgICAgICAgbmVzdCA9IFRSVUUpICU+JQogIHN1bW1hcml6ZShlY2lnX2V2ZXJfeWVhciA9IHN1cnZleV9tZWFuKGVjaWdfZXZlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksCiAgICAgICAgbm9uX2VjaWdfZXZlcl95ZWFyID0gc3VydmV5X21lYW4obm9uX2VjaWdfZXZlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpICU+JQogIG11dGF0ZV9hbGwoIioiLCAxMDApICU+JQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksCiAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLAogICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oc3RyX2RldGVjdChDYXRlZ29yeSwgIl9sb3ciKSB+ICJMb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoQ2F0ZWdvcnksICJfdXBwIikgfiAiVXBwZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSwKICAgICAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChDYXRlZ29yeSwgImV2ZXIiKSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChDYXRlZ29yeSwgImN1cnJlbnQiKSB+ICJDdXJyZW50IiksCiAgICAgIFByb2R1Y3QgPSBjYXNlX3doZW4oc3RyX2RldGVjdChDYXRlZ29yeSwgIm5vbl9lY2lnIikgfiAiT3RoZXIgcHJvZHVjdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkUtY2lnYXJldHRlcyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1DYXRlZ29yeSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgKX0KCm55dHNfZGF0YSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBncm91cF9tb2RpZnkofiBzdXJ2ZXlNZWFuQigueCkpICU+JQogIGhlYWQoKQoKCnBsb3RCX3cgPC0gbnl0c19kYXRhICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIGdyb3VwX21vZGlmeSh+IHN1cnZleU1lYW5CKC54KSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IE1lYW4sIGNvbG9yID0gUHJvZHVjdCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBMb3dlciwgeW1heCA9IFVwcGVyKSwgc2l6ZSA9IDEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLCAxKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNjAsIGJ5ID0gMTApLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCA2MCkpICsKICAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKHRpdGxlID0gIiUgRXZlciB0cnlpbmcgZS1jaWdhcmV0dGVzIGluY3JlYXNlcyAmCiUgRXZlciB0cnlpbmcgb3RoZXIgcHJvZHVjdHMgZGVjcmVhc2VzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RCX3cKYGBgCgoKTm93IHdlIHdpbGwgZG8gdGhlIHNhbWUgYnV0IGZvciBjdXJyZW50IHVzZXJzOgoKYGBge3J9CnN1cnZleU1lYW5DIDwtIGZ1bmN0aW9uKGN1cnJZZWFyKSB7CiAgb3B0aW9ucyhzdXJ2ZXkubG9uZWx5LnBzdSA9ICJhZGp1c3QiKQogIGN1cnJZZWFyICU+JQogIGFzX3N1cnZleV9kZXNpZ24oc3RyYXRhID0gc3RyYXR1bSwKICAgICAgICAgICAgICAgICAgICAgIGlkcyA9IHBzdSwKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwKICAgICAgICAgICAgICAgICAgICAgbmVzdCA9IFRSVUUpICU+JQogIHN1bW1hcml6ZShlY2lnX2N1cnJlbnRfeWVhciA9IHN1cnZleV9tZWFuKGVjaWdfY3VycmVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksCiAgICAgICAgbm9uX2VjaWdfY3VycmVudF95ZWFyID0gc3VydmV5X21lYW4obm9uX2VjaWdfY3VycmVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFydHlwZSA9ICJjaSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpICU+JQogIG11dGF0ZV9hbGwoIioiLCAxMDApICU+JQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksCiAgICAgICAgICAgbmFtZXNfdG8gPSAiQ2F0ZWdvcnkiLAogICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBtdXRhdGUoRXN0aW1hdGUgPSBjYXNlX3doZW4oc3RyX2RldGVjdChDYXRlZ29yeSwgIl9sb3ciKSB+ICJMb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoQ2F0ZWdvcnksICJfdXBwIikgfiAiVXBwZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk1lYW4iKSwKICAgICAgICAgICAgIFVzZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChDYXRlZ29yeSwgImV2ZXIiKSB+ICJFdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChDYXRlZ29yeSwgImN1cnJlbnQiKSB+ICJDdXJyZW50IiksCiAgICAgIFByb2R1Y3QgPSBjYXNlX3doZW4oc3RyX2RldGVjdChDYXRlZ29yeSwgIm5vbl9lY2lnIikgfiAiT3RoZXIgcHJvZHVjdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkUtY2lnYXJldHRlcyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1DYXRlZ29yeSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYFBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHNgKX0KCgpwbG90Q193IDwtIG55dHNfZGF0YSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBncm91cF9tb2RpZnkofiBzdXJ2ZXlNZWFuQygueCkpICU+JQogICAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IE1lYW4sIGNvbG9yID0gUHJvZHVjdCkpICsKICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlID0gImRhc2hlZCIpKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBMb3dlciwgeW1heCA9IFVwcGVyKSwgCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLCAgCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgYnkgPSAxMCksIGxpbWl0cyA9IGMoMCwgNjApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICIlIEN1cnJlbnRseSB1c2luZyBlLWNpZ2FyZXR0ZXMgaW5jcmVhc2VzICYKJSBDdXJyZW50bHkgdXNpbmcgb3RoZXIgcHJvZHVjdHMgZGVjcmVhc2VzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKcGxvdENfdwpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CiNjb2RlIHRvIGNyZWF0ZSBwcm9wZXIgbGVnZW5kIGZvciBpbnN0cnVjdG9ycyBzdGFydGluZyBhdCBzdXJ2ZXkgd2VpZ2h0aW5nIHNlY3Rpb24KCgpwbG90MWMgPC0gbnl0c19kYXRhICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHllYXIpICU+JQogICAgZHBseXI6OnN1bW1hcml6ZSgiRXZlcl9FLWNpZ2FyZXR0ZSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihlY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X0UtY2lnYXJldHRlIiA9IAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKGVjaWdfb25seV9jdXJyZW50LCBuYS5ybSA9IFRSVUUpICogMTAwKSwKICAgICAgICAgICAgICAgICAgICAgIkV2ZXJfTm9uLWUtY2lnYXJldHRlIiA9IAogICAgICAgICAgICAgICAgICAgICAgIChtZWFuKG5vbl9lY2lnX29ubHlfZXZlciwgbmEucm0gPSBUUlVFKSAqIDEwMCksCiAgICAgICAgICAgICAgICAgICAgICJDdXJyZW50X05vbi1lLWNpZ2FyZXR0ZSIgPSAKICAgICAgICAgICAgICAgICAgICAgICAobWVhbihub25fZWNpZ19vbmx5X2N1cnJlbnQsIG5hLnJtID0gVFJVRSkgKiAxMDApKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC0geWVhciwgCiAgICAgICAgICAgbmFtZXNfdG8gPSAiVXNlciIsIAogICAgICAgICAgdmFsdWVzX3RvID0gIlBlcmNlbnRhZ2Ugb2Ygc3R1ZGVudHMiKSAlPiUKICBzZXBhcmF0ZShVc2VyLCBpbnRvID0gYygiVXNlciIsICJQcm9kdWN0IiksIHNlcCA9ICJfIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCAKICAgICAgICAgICAgICAgeSA9IGBQZXJjZW50YWdlIG9mIHN0dWRlbnRzYCwgCiAgICAgICAgICAgY29sb3IgPSBQcm9kdWN0KSkgKwogICAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZSA9IFVzZXIpKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gMikgKwogICMgdGhpcyBhbGxvd3MgdXMgdG8gY2hvb3NlIHdoYXQgdHlwZSBvZiBsaW5lIHdlIHdhbnQgZm9yIGVhY2ggbGluZQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgIyB0aGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IGhvdyB0aGUgeS1heGlzIHNob3VsZCBhcHBlYXIKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDMwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDAsIDMwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAzMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdl9jb2xvcnMpICsKICAjIHRoaXMgYWRqdXN0cyB0aGUgYmFja2dyb3VuZCBzdHlsZSBvZiB0aGUgcGxvdAogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgIyB0aGlzIG1vdmVzIHRoZSBsZWdlbmQgdG8gdGhlIGJvdHRvbSBvZiB0aGUgcGxvdCBhbmQgcmVtb3ZlcyB0aGUgeCBheGlzIHRpdGxlCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICJIb3cgaGFzIHVzZSBvZiBvbmx5IGUtY2lnYXJldHRlcyBhbmQKb25seSB0b2JhY2NvIHByb2R1Y3RzIGJlc2lkZXMgZS1jaWdhcmV0dGVzIHZhcmllZCBvdmVyIHRpbWU/IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCmBgYAoKCgoKTm93IHdlIHdpbGwgcHV0IHRoZXNlIHBsb3RzIHRvZ2V0aGVyIGFnYWluIHVzaW5nIHRoZSBgY293cGxvdGAgcGFja2FnZToKCmBgYHtyfQp0aXRsZV93IDwtIGdnZHJhdygpICsKICBkcmF3X2xhYmVsKAogICAgZXhwcmVzc2lvbigiV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZS1jaWdhcmV0dGUgdXNlIGFuZCB0b2JhY2NvIHVzZT8iKSwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgc2l6ZSA9IDE0LAogICAgeCA9IDAsCiAgICBoanVzdCA9IDAKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdHNBX3cgPC0gcGxvdF9ncmlkKHBsb3RBX3csCiAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEpLAogICAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJ2IiwKICAgICAgICAgICAgICAgICAgICAgYXhpcyA9ICJidCIpCnBsb3RzQkNfdyA8LSBwbG90X2dyaWQocGxvdEJfdywKICAgICAgICAgICAgICAgICAgICAgcGxvdENfdywKICAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSwgMSksCiAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gInYiLAogICAgICAgICAgICAgICAgICAgICBheGlzID0gImJ0IikKCmxlZ2VuZF93IDwtIGdldF9sZWdlbmQocGxvdDFjICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSkKCmZpZ3VyZV93IDwtIHBsb3RfZ3JpZCh0aXRsZV93LAogICAgICAgICAgICAgICAgICAgICAgcGxvdHNBX3csCiAgICAgICAgICAgICAgICAgICAgICBwbG90c0JDX3csCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfdywKICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4xKSwKICAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gMS4wKQoKZmlndXJlX3cKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlc2UgZmlndXJlcyBsb29rIHF1aXRlIHNpbWlsYXIgdG8gdGhlIG9uZXMgZ2VuZXJhdGVkIHdpdGhvdXQgdXNpbmcgdGhlIHN1cnZleSB3ZWlnaHRzLgoKIyMjICoqQXJ0aWZpY2lhbCBDb2hvcnQqKgoqKioKCkFsdGhvdWdoIHRoZSBzdXJ2ZXkgZGVzaWduIGRvZXMgbm90IGFsbG93IHNwZWNpZmljIGluZGl2aWR1YWxzIHRvIGJlIGZvbGxvd2VkIG92ZXIgdGltZSwgd2Ugd2lsbCB1c2UgY2VydGFpbiBzdWJzZXRzIG9mIHRoZSBkYXRhIGZyb20gZWFjaCB5ZWFyIHRvIGNvbnN0cnVjdCBhbiBhcnRpZmljaWFsIGNvaG9ydCB3aGVyZSB3ZSBmb2xsb3cgc3R1ZGVudHMgb2YgdGhlIHNhbWUgYWdlIGdyb3VwIGFzIHRoZXkgZ2V0IG9sZGVyLiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gbG9vayBhdCBob3cgdG9iYWNjbyB1c2FnZSBjaGFuZ2VkIGZvciBzdHVkZW50cyB3aG8gd2VyZSBpbiA4dGggZ3JhZGUgaW4gMjAxNSBhcyB0aGV5IGFnZWQuIAoKQWxsIG9mIHRoZSBkYXRhIHNvIGZhciBoYXMgaW5jbHVkZWQgYWxsIDZ0aC0xMnRoIGdyYWRlcnMgZXZlcnkgeWVhci4gTm93IHdlIHdpbGwgbG9vayBhdCBqdXN0IHRoZSBkYXRhIGZvciBzdHVkZW50cyBleHBlY3RlZCB0byBncmFkdWF0ZSBpbiAyMDE5LiBUaGVzZSBhcmUgdGhlIHN0dWRlbnRzIHdobyB3ZXJlIGluIDh0aCBncmFkZSBpbiAyMDE1LCBtb3N0IG9mIHdob20gd2VyZSA5dGggZ3JhZGVycyBpbiAyMDE2LCAxMHRoIGdyYWRlcnMgaW4gMjAxNyBhbmQgc28gb24uIFdlIHdpbGwgZmlsdGVyIHRoZSBkYXRhIHRvIGp1c3QgdGhlIHN0dWRlbnRzIGV4cGVjdGVkIHRvIGJlIGluIHRoZSBncmFkdWF0aW5nIGNsYXNzIG9mIDIwMTkuCgoKYGBge3J9CgpzdXJ2ZXlNZWFuQ29ob3J0IDwtIGZ1bmN0aW9uKGN1cnJZZWFyKSB7CiAgb3B0aW9ucyhzdXJ2ZXkubG9uZWx5LnBzdSA9ICJhZGp1c3QiKQogIGN1cnJZZWFyICU+JQogIGFzX3N1cnZleV9kZXNpZ24oc3RyYXRhID0gc3RyYXR1bSwKICAgICAgICAgICAgICAgICAgICAgIGlkcyA9IHBzdSwKICAgICAgICAgICAgICAgICAgd2VpZ2h0ICA9IGZpbndndCwKICAgICAgICAgICAgICAgICAgICAgbmVzdCA9IFRSVUUpICU+JQogIHN1bW1hcml6ZShlY2lnX2V2ZXJfeWVhciA9IAogICAgICAgICAgICAgIHN1cnZleV9tZWFuKGVjaWdfZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGVjaWdfY3VycmVudF95ZWFyID0gCiAgICAgICAgICAgICAgc3VydmV5X21lYW4oZWNpZ19jdXJyZW50LCB2YXJ0eXBlID0gImNpIiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbm9uX2VjaWdfZXZlcl95ZWFyID0gCiAgICAgICAgICAgICAgc3VydmV5X21lYW4obm9uX2VjaWdfZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5vbl9lY2lnX2N1cnJlbnRfeWVhciA9IAogICAgICAgICAgICAgIHN1cnZleV9tZWFuKG5vbl9lY2lnX2N1cnJlbnQsIHZhcnR5cGUgPSAiY2kiLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB0b2JhY2NvX2V2ZXJfeWVhciA9IAogICAgICAgICAgICAgIHN1cnZleV9tZWFuKHRvYmFjY29fZXZlciwgdmFydHlwZSA9ICJjaSIsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHRvYmFjY29fY3VycmVudF95ZWFyID0gCiAgICAgICAgICAgICAgc3VydmV5X21lYW4odG9iYWNjb19jdXJyZW50LCB2YXJ0eXBlID0gImNpIiwgbmEucm0gPSBUUlVFKSkgJT4lCiAgbXV0YXRlX2FsbCgiKiIsIDEwMCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwKICAgICAgICAgICBuYW1lc190byA9ICJDYXRlZ29yeSIsCiAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSBvZiBzdHVkZW50cyIpICU+JQogIG11dGF0ZShFc3RpbWF0ZSA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KENhdGVnb3J5LCAiX2xvdyIpIH4gIkxvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChDYXRlZ29yeSwgIl91cHAiKSB+ICJVcHBlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTWVhbiIpLAogICAgICAgICAgICAgVXNlciA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KENhdGVnb3J5LCAiZXZlciIpIH4gIkV2ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KENhdGVnb3J5LCAiY3VycmVudCIpIH4gIkN1cnJlbnQiKSwKICAgICAgUHJvZHVjdCA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KENhdGVnb3J5LCAibm9uX2VjaWciKSB+ICJPdGhlciBwcm9kdWN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoQ2F0ZWdvcnksICJ0b2JhY2NvIikgfiAiQW55IHRvYmFjY28gcHJvZHVjdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiRS1jaWdhcmV0dGVzIikpICU+JQogIGRwbHlyOjpzZWxlY3QoLUNhdGVnb3J5KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gRXN0aW1hdGUsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBgUGVyY2VudGFnZSBvZiBzdHVkZW50c2ApfQoKCkNvaG9ydF9kYXRhIDwtIG55dHNfZGF0YSAlPiUKICBmaWx0ZXIoKEdyYWRlID09ICI4IiAmIHllYXIgPT0gMjAxNSkgfAogICAgICAgICAoR3JhZGUgPT0gIjkiICYgeWVhciA9PSAyMDE2KSB8CiAgICAgICAgIChHcmFkZSA9PSAiMTAiICYgeWVhciA9PSAyMDE3KSB8CiAgICAgICAgIChHcmFkZSA9PSAiMTEiICYgeWVhciA9PSAyMDE4KSB8CiAgICAgICAgICAoR3JhZGUgPT0gIjEyIiAmIHllYXIgPT0gMjAxOSkKICAgICAgICAgKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBncm91cF9tb2RpZnkofiBzdXJ2ZXlNZWFuQ29ob3J0KC54KSkKCmhlYWQoQ29ob3J0X2RhdGEpCmBgYAoKV2Ugd2lsbCBub3cgbWFrZSBzaW1pbGFyIHBsb3RzIHRvIHRob3NlIGFib3ZlIGZvciB0aGlzIHN1YnNldCBvZiB0aGUgZGF0YToKCmBgYHtyfQpwbG90QV93XzggPC0gQ29ob3J0X2RhdGEgJT4lCiAgZmlsdGVyKFByb2R1Y3QgPT0gIkFueSB0b2JhY2NvIHByb2R1Y3QiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gTWVhbikpICsKICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlID0gVXNlcikpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IExvd2VyLCB5bWF4ID0gVXBwZXIpLCBzaXplID0gMSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDcwLCBieSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMCwgNzAsIGJ5ID0gMTApLAogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgNzApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICJUb2JhY2NvIHByb2R1Y3QgdXNlIGJlY2FtZSBpbmNyZWFzaW5nbHkgcHJldmFsZW50IiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RCX3dfOCA8LSBDb2hvcnRfZGF0YSAlPiUKICBmaWx0ZXIoUHJvZHVjdCAhPSAiQW55IHRvYmFjY28gcHJvZHVjdCIsIFVzZXIgPT0gIkV2ZXIiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gTWVhbiwgY29sb3IgPSBQcm9kdWN0KSkgKwogIGdlb21fbGluZShsaW5ldHlwZSA9IDEpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IExvd2VyLCB5bWF4ID0gVXBwZXIpLCBzaXplID0gMSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMTAsIDYwLCBieSA9IDEwKSwgbGltaXRzID0gYygxMCwgNjApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHZfY29sb3JzKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9ICIlIGV2ZXIgdHJ5aW5nIHRvYmFjY28gcHJvZHVjdHMgaW5jcmVhc2VzIiwKICAgICAgICAgeSA9ICIlIG9mIHN0dWRlbnRzIikKCnBsb3RDX3dfOCA8LSBDb2hvcnRfZGF0YSAlPiUKICBmaWx0ZXIoUHJvZHVjdCAhPSAiQW55IHRvYmFjY28gcHJvZHVjdCIsIFVzZXIgPT0gIkN1cnJlbnQiKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBNZWFuLCBjb2xvciA9IFByb2R1Y3QpKSArCiAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZSA9IFVzZXIpKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBMb3dlciwgeW1heCA9IFVwcGVyKSwgc2l6ZSA9IDEpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLCAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNjAsIGJ5ID0gMTApLCBsaW1pdHMgPSBjKDAsIDYwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB2X2NvbG9ycykgKwogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSAiRS1jaWdhcmV0dGUgdXNlIHN1cnBhc3NlcyB1c2Ugb2Ygb3RoZXIgcHJvZHVjdHMiLAogICAgICAgICB5ID0gIiUgb2Ygc3R1ZGVudHMiKQoKdGl0bGVfd184IDwtIGdnZHJhdygpICsKICBkcmF3X2xhYmVsKAogIGV4cHJlc3Npb24oIkZvciBzdHVkZW50cyBpbiB0aGUgMjAxOSBncmFkdWF0aW5nIGNsYXNzLCBob3cgYXJlIHZhcGluZyBhbmQgdG9iYWNjbyB1c2UgcmVsYXRlZD8iKSwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgc2l6ZSA9IDE0LAogICAgeCA9IDAsCiAgICBoanVzdCA9IDAKICApICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdHNBX3dfOCA8LSBwbG90X2dyaWQocGxvdEFfd184LAogICAgICAgICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygxKSwKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAidiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMgPSAiYnQiKQoKcGxvdHNCQ193XzggPC0gcGxvdF9ncmlkKHBsb3RCX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RDX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgYXhpcyA9ICJidCIpCgpsZWdlbmRfd184IDwtIGdldF9sZWdlbmQocGxvdDFjICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSkKCmZpZ3VyZV93XzggPC0gcGxvdF9ncmlkKHRpdGxlX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdHNBX3dfOCwKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdHNCQ193XzgsCiAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF93XzgsCiAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjEpLAogICAgICAgICAgICAgICAgICAgICAgICBzY2FsZSA9IDEuMAopCgpmaWd1cmVfd184CmBgYAoKCgojIyAqKkRhdGEgQW5hbHlzaXMqKgoqKiogCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojSWYgaW5zdHJ1Y3RvcnMgc3RhcnQgaGVyZSwgd2UgbmVlZCB0byBsb2FkIHRoZSBkYXRhOgpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWRfZGF0YV93aXRoX3Zhcl9mb3JfcGxvdHMucmRhIikpCmBgYAoKQXMgYW4gZXh0ZW5zaW9uLCB3ZSB3aWxsIGluY2x1ZGUgc29tZSBtYXRlcmlhbCBoZXJlIG9uIFtsb2dpc3RpYyByZWdyZXNzaW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb2dpc3RpY19yZWdyZXNzaW9uKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBzdXJ2ZXktd2VpZ2h0ZWQgbG9naXN0aWMgcmVncmVzc2lvbiB0aGF0IHdvdWxkIGJlIGFwcHJvcHJpYXRlIGZvciBhbnN3ZXJpbmcgUXVlc3Rpb24gMiAoIkhvdyBkb2VzIGUtY2lnYXJldHRlIHVzZSBjb21wYXJlIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXM/IikgZm9yIGEgc2luZ2xlIHllYXIgdXNpbmcgc3RhdGlzdGljYWwgaW5mZXJlbmNlLCByYXRoZXIgdGhhbiBqdXN0IGRhdGEgdmlzdWFsaXphdGlvbnMuCgpXZSBjYW4gbG9vayBhdCB0aGUgZmluYWwgZmlndXJlIGluIHRoZSBzZWN0aW9uIG9uIFF1ZXN0aW9uIDIgYW5kIHNlZSB0aGF0IGFtb25nIGJvdGggY3VycmVudCBhbmQgZXZlciB1c2VycyBvZiBlLWNpZ2FyZXR0ZXMsIGEgaGlnaGVyIHBlcmNlbnRhZ2Ugb2YgbWFsZXMgdGhhbiBmZW1hbGVzIHVzZSBvciBoYXZlIHVzZWQgZS1jaWdhcmV0dGVzLicKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicGxvdDIucG5nIikpCmBgYAoKQnV0IHdoYXQgaWYgd2Ugd2FudGVkIHRvIHF1YW50aWZ5IHRoaXMgZWZmZWN0IGFuZCBhc3Nlc3Mgd2hldGhlciB0aGlzIGRpZmZlcmVuY2UgY2FuIGJlIGNvbnNpZGVyZWQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudD8gVGhpcyBpcyB3aGVyZSB0aGUgdG9vbCBvZiBsb2dpc3RpYyByZWdyZXNzaW9uIGNhbiBjb21lIGluIGhhbmR5LgoKIyMjICoqTG9naXN0aWMgcmVncmVzc2lvbiBtb3RpdmF0aW9uKioKKioqCgpIZXJlLCB3ZSB3aWxsIGFwcHJvYWNoIHRoZSB0b3BpYyBvZiBbbG9naXN0aWMgcmVncmVzc2lvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTG9naXN0aWNfcmVncmVzc2lvbil7dGFyZ2V0PSJfYmxhbmsifSBhc3N1bWluZyBzb21lIHByaW9yIGtub3dsZWRnZSBvZiBzaW1wbGUgYW5kIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uLiBUaGVzZSBoYXZlIGJlZW4gY292ZXJlZCBpbiBbYW5vdGhlciBjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLWRpZXQvKS4KCkFzIGEgYnJpZWYgcmVtaW5kZXIsIGEgW2xpbmVhciByZWdyZXNzaW9uIG1vZGVsXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaW5lYXJfcmVncmVzc2lvbil7dGFyZ2V0PSJfYmxhbmsifSBhbGxvd3MgdXMgdG8gZXN0aW1hdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFuIG91dGNvbWUgdmFyaWFibGUsIGNhbGwgaXQgJFkkLCBhbmQgYSBzZXQgb2Ygb25lIG9yIG1vcmUgaW5wdXQgdmFyaWFibGVzLCAkWF8xLCBYXzIsIC4uLiwgWF9uJC4gV2UgY2FuIHdyaXRlIGEgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGFzOgoKJCQgRShZKSA9IFxiZXRhXzAgKyBcYmV0YV8xIFhfMSQkCgp3aGVyZSB0aGUgJEUoWSkkIG1lYW5zIHRoZSBleHBlY3RlZCB2YWx1ZSBvZiAkWSQsIGkuZS4sIG91ciBtb2RlbCBnaXZlcyB1cyBhbiBlc3RpbWF0ZSBvZiB0aGUgbWVhbiB2YWx1ZSBvZiAkWSQgZ2l2ZW4gYSBwYXJ0aWN1bGFyIGlucHV0ICRYXzEkLiBIZXJlLCAkXGJldGFfMSQgcXVhbnRpZmllcyB0aGUgZXhwZWN0ZWQgZGlmZmVyZW5jZSBpbiAkWSQgY29tcGFyaW5nIHR3byBpbmRpdmlkdWFscyB3aG8gYXJlIG9uZSB1bml0IGFwYXJ0IGluICRYXzEkLgoKU2ltaWxhcmx5LCB3ZSBjYW4gaW5jbHVkZSBtb3JlIHRoYW4gb25lIHByZWRpY3RvciBzbyB0aGF0IG91ciBlcXVhdGlvbiBtaWdodCBsb29rIGxpa2U6CgokJCBFKFkpID0gXGJldGFfMCArIFxiZXRhXzEgWF8xICsgXGJldGFfMiBYXzIkJAoKSGVyZSwgJFxiZXRhXzEkIHF1YW50aWZpZXMgdGhlIGV4cGVjdGVkIGRpZmZlcmVuY2UgaW4gJFkkIGNvbXBhcmluZyB0d28gaW5kaXZpZHVhbHMgd2hvIGFyZSBvbmUgdW5pdCBhcGFydCBpbiAkWF8xJCwgaG9sZGluZyAkWF8yJCBhdCBhIGZpeGVkIHZhbHVlLiBUaGlzIG1hdGVyaWFsIGlzIGNvdmVyZWQgaW4gbW9yZSBkZXRhaWwgW2Vsc2V3aGVyZV0oaHR0cHM6Ly9yYWZhbGFiLmdpdGh1Yi5pby9kc2Jvb2svbGluZWFyLW1vZGVscy5odG1sI2xpbmVhci1yZWdyZXNzaW9uLWluLXRoZS10aWR5dmVyc2Upe3RhcmdldD0iX2JsYW5rIn0gYW5kIGluIFthbm90aGVyIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtZGlldC8pe3RhcmdldD0iX2JsYW5rIn0uCgpJbiB0aGUgY2FzZSBvZiBvdXIgcXVlc3Rpb24gb2YgaW50ZXJlc3QgZm9yIHRoaXMgY2FzZSBzdHVkeSwgaG93ZXZlciwgb3VyIG91dGNvbWUgdmFyaWFibGUgaXMgb2YgYSBwYXJ0aWN1bGFyIHR5cGU6IGl0IGlzIGEgWWVzLU5vIG9yICpiaW5hcnkqIG91dGNvbWUsIHNpbmNlIGVhY2ggc3R1ZGVudCByZXNwb25kZW50IGVpdGhlciBpcyBvciBpcyBub3QgYSBjdXJyZW50IHVzZXIgb2YgZS1jaWdhcmV0dGVzLiBUaGlzIG1lYW5zIGluIG91ciBzZXR0aW5nICRZJCBvbmx5IHRha2VzIG9uIHR3byB2YWx1ZXM6IFRSVUUgb3IgRkFMU0UsIHdoaWNoIHdlIGNhbiBhbHNvIHRoaW5rIG9mIGFzIDEgYW5kIDAuIEZvciB0aGlzIGtpbmQgb2Ygb3V0Y29tZSB2YXJpYWJsZSwgd2UgbmVlZCBhIHNwZWNpYWwga2luZCBvZiByZWdyZXNzaW9uLCBjYWxsZWQgKmxvZ2lzdGljIHJlZ3Jlc3Npb24qLiBBbmQgaW5zdGVhZCBvZiB1c2luZyBhIGxpbmVhciBtb2RlbCB0byBlc3RpbWF0ZSAkWSQgaXRzZWxmIGZvciBhIGdpdmVuIHNldCBvZiBpbnB1dCB2YXJpYWJsZXMsIHdlIHdpbGwgdXNlIGEgbGluZWFyIG1vZGVsIHRvIGVzdGltYXRlIHRoZSAqbG9nIG9kZHMgdGhhdCBZPTEqIGZvciBhIGdpdmVuIHNldCBvZiBpbnB1dCB2YXJpYWJsZXMuCgpJZiB3ZSBkZWZpbmUgJHA9UChZPTEpPUUoWSkkLCB0aGUgc3RhbmRhcmQgc2ltcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZXF1YXRpb24gY2FuIGJlIHdyaXR0ZW4gYXM6CgokJGxvZ2l0KHApPSBsb2dfZSAoXGZyYWN7cH17MS1wfSk9IFxiZXRhXzAgKyBcYmV0YV8xIFgkJCAgCgpJbiBvdXIgY2FzZSwgd2Ugd291bGQgZGVmaW5lICRwJCBhcyB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIHN0dWRlbnQgcmVzcG9uZGVudCBpcyBhIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlciwgc2luY2UgJFkkIGlzIHRoZSBiaW5hcnkgdmFyaWFibGUgdGhhdCBpcyAxIHdoZW4gYSBzdHVkZW50IHJlc3BvbmRlbnQgaXMgYSBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgYW5kIDAgaWYgbm90LiBUaGUgdmFsdWUgJFxmcmFje3B9ezEtcH0kIGlzIGNhbGxlZCB0aGUgKm9kZHMqIHRoYXQgJFkkIGlzIGVxdWFsIHRvIDEuCgpUaGlzICpsb2dpdCogZnVuY3Rpb24gaXMgc2hvcnQgZm9yICpsb2cgb2RkcyouIAoKV2hpbGUgaXQgbWF5IGZlZWwgc3RyYW5nZSB3b3JraW5nIHdpdGggdGhlIGxvZyBvZGRzIHRoYXQgb3VyIG91dGNvbWUgdmFyaWFibGUgaXMgZXF1YWwgdG8gMSwgdGhlcmUgYXJlIHNvbWUgaW50dWl0aXZlIHJlYXNvbnMgd2h5IGl0IG1ha2VzIHNlbnNlIHRvIGRvIHRoaXMgZnJvbSB0aGUgcG9pbnQgb2YgdmlldyBvZiBmaXR0aW5nIGEgbGluZSB0byBvdXIgZGF0YSBhbmQgaW50ZXJwcmV0aW5nIHRoZSByZXN1bHRzLiBUaGUgW2xvZyBvZGRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb2dpdCl7dGFyZ2V0PSJfYmxhbmsifSBjYW4gdGFrZSBhbnkgdmFsdWUgb24gdGhlIHJlYWwgbnVtYmVyIGxpbmUsIGFsbG93aW5nIHVzIHRvIGVzdGltYXRlIG91ciBtb2RlbCBwYXJhbWV0ZXJzIHdpdGggbm8gY29uc3RyYWludHMuIElmIHdlIGluc3RlYWQgdHJpZWQgdG8gdXNlIHNheSAkcCQgYXMgdGhlIG91dGNvbWUgdmFyaWFibGUsIHdlIHdvdWxkIHNvbWVob3cgbmVlZCB0byBjb25zdHJhaW4gJFxiZXRhXzAgKyBcYmV0YV8xIFgkIHRvIGJlIGJldHdlZW4gMCBhbmQgMSwgc2luY2UgdGhpcyBpcyB0aGUgb25seSBwb3NzaWJsZSByYW5nZSBvZiB2YWx1ZXMgZm9yIGEgW3Byb2JhYmlsaXR5XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Qcm9iYWJpbGl0eSl7dGFyZ2V0PSJfYmxhbmsifS4gQSBzZWNvbmQsIG1vcmUgdGVjaG5pY2FsIHJlYXNvbiBpcyB0aGF0IHdvcmtpbmcgb24gdGhlIGxvZyBvZGRzIHNjYWxlIGdpdmVzIHVzIGEgbmljZSBmb3JtdWxhdGlvbiBvZiBvdXIgKmxpa2VsaWhvb2QqLCBpLmUuLCBhIGZ1bmN0aW9uIG9mIG91ciB1bmtub3duIHBhcmFtZXRlcnMgdGhhdCBpbmNvcnBvcmF0ZXMgb3VyIG9ic2VydmVkIGRhdGEuIFdlIHVzZSB0aGlzIFtsaWtlbGlob29kIGZ1bmN0aW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaWtlbGlob29kX2Z1bmN0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9IHRvIGVzdGltYXRlIG91ciB1bmtub3duIHBhcmFtZXRlcnMgKGhlcmUsICRcYmV0YV8wJCBhbmQgJFxiZXRhXzEkKSBhbmQgdGhpcyBmb3JtdWxhdGlvbiBnaXZlcyB1cyBhIG5pY2Ugd2F5IHRvIGNhbGN1bGF0ZSB0aGUgW21heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01heGltdW1fbGlrZWxpaG9vZF9lc3RpbWF0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9IG9mIHRoZXNlIHBhcmFtZXRlcnMuCgpUaGUgaW50dWl0aXZlIGV4cGxhbmF0aW9uIG9mIGxvZ2lzdGljIHJlZ3Jlc3Npb24gdGhlbiBpcyB0aGF0IHdlIGFyZSBmaXR0aW5nIGEgbGluZSB0byB0aGUgbG9nIG9kZHMgb2YgJFkkLCBhcyBpdCB2YXJpZXMgd2l0aCBkaWZmZXJlbnQgdmFsdWVzIG9mICRYJC4gV2Ugd2lsbCB3b3JrIHRocm91Z2ggYW4gZXhhbXBsZSBiZWxvdyB0byBpbGx1c3RyYXRlIGFuZCBob3BlZnVsbHkgY2xhcmlmeSB0aGlzLgoKCiMjIyAqKkxvZ2lzdGljIHJlZ3Jlc3Npb24gImJ5IGhhbmQiIGFuZCBieSBtb2RlbCoqCioqKgoKRm9yIHNpbXBsaWNpdHksIHdlIHdpbGwgY29uc2lkZXIganVzdCB0aGUgc2V0IG9mIGN1cnJlbnQgdXNlcnMgb2YgZS1jaWdhcmV0dGVzIGluIDIwMTUuIEhvdyBtdWNoIG1vcmUgbGlrZWx5IGlzIGEgbWFsZSBzdHVkZW50IHRvIGJlIGEgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VyIHRoYW4gYSBmZW1hbGUgc21va2VyPwoKV2UgY2FuIGdldCBhIGZpcnN0IGxvb2sgYXQgdGhlIGFuc3dlciBieSBjYWxjdWxhdGluZyB0aGUgcGVyY2VudCBvZiBmZW1hbGVzIGFuZCBwZXJjZW50IG9mIG1hbGVzIHdobyBhcmUgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VycyBvciBub3Q6IAoKYGBge3J9Cm55dHNfZGF0YSAlPiUgCiAgZmlsdGVyKHllYXIgPT0gMjAxNSwgIWlzLm5hKFNleCkpICU+JQogIGdyb3VwX2J5KFNleCwgZWNpZ19jdXJyZW50KSAlPiUKICBzdW1tYXJpemUobiA9IG4oKSkgJT4lCiAgbXV0YXRlKHBjdCA9IG4gLyBzdW0obikpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBwZXJjZW50YWdlIGlzIGxvd2VyIGZvciBmZW1hbGVzIHRoYW4gZm9yIG1hbGVzLiBBbm90aGVyIHdheSBvZiBvcmdhbml6aW5nIHRoaXMgZGF0YSB3b3VsZCBiZSB0byBtYWtlIGEgWzJ4MiB0YWJsZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29udGluZ2VuY3lfdGFibGUpe3RhcmdldD0iX2JsYW5rIn0sIGEgZGF0YSBzdW1tYXJpemF0aW9uIGZyZXF1ZW50bHkgdXNlZCBpbiBwdWJsaWMgaGVhbHRoIHNldHRpbmdzLgoKfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWFsZSAgICAgfCBGZW1hbGV8IFRvdGFsfAp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLTp8LS0tLS0tOnwtLS0tLTp8CnxDdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgICAgICAgICB8ICAgICAgMTE3MXwgICAgNzcyfCAgMTk0M3wKfE5vdCBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgICAgIHwgICAgICA3Nzg3fCAgIDc4NTB8IDE1NjM3fAp8VG90YWwgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgIDg5NTh8ICAgODYyMnwgMTc1ODB8CgoKQXMgZGlzY3Vzc2VkIGFib3ZlLCBvbmUgaW1wb3J0YW50IGluZ3JlZGllbnQgaW4gdW5kZXJzdGFuZGluZyB0aGUgb3V0cHV0IG9mIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaXMgdW5kZXJzdGFuZGluZyB0aGUgY29uY2VwdCBvZiBhbiBvZGRzIGFuZCBhbiBvZGRzIHJhdGlvLiBXZSBjYW4gYXNrLCBhbW9uZyBtYWxlcyB3aG8gcmVzcG9uZGVkIHRvIHRoZSBzdXJ2ZXkgaW4gMjAxNSwgd2hhdCBhcmUgdGhlIG9kZHMgb2YgYmVpbmcgYSBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXI/IEhvdyBhYm91dCBmb3IgZmVtYWxlcz8gSG93IGRvIHRoZXNlIG9kZHMgY29tcGFyZT8gVGhlIFtvZGRzIHJhdGlvXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PZGRzX3JhdGlvKXt0YXJnZXQ9Il9ibGFuayJ9IGlzIGEgdG9vbCBmcmVxdWVudGx5IHVzZWQgaW4gcHVibGljIGhlYWx0aCB0byBjb21wYXJlIHRoZSBvZGRzIGJldHdlZW4gdHdvIGdyb3Vwcy4gCgpJbiB0aGlzIGNhc2U6CgoqIE9kZHMgb2YgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2UgZm9yIG1hbGVzOiAxMTcxIC8gNzc4NyA9IDAuMTUwCiogT2RkcyBvZiBjdXJyZW50IGUtY2lnYXJldHRlIHVzZSBmb3IgZmVtYWxlczogNzcyIC8gNzg1MCA9IDAuMDk4CiogT2RkcyByYXRpbyBvZiBlLWNpZ2FyZXR0ZSB1c2UgZm9yIGZlbWFsZXMgYXMgY29tcGFyZWQgdG8gbWFsZXM6ICQkT1IgPSBcZnJhY3tvZGRzIFwgZm9yIFwgZmVtYWxlc317b2RkcyBcIGZvciBcIG1hbGVzfSA9IFxmcmFjezc3MiAvIDc4NTB9ezExNzEgLyA3Nzg3fSA9IDAuNjUkJAoqIExvZyBvZGRzIHJhdGlvOiAkbG9nX2UoT1IpID0gbG9nKDEuNTMpID0gLTAuNDIkCgpXZSB3b3VsZCBpbnRlcnByZXQgdGhlc2UgdmFsdWVzIGJ5IHNheWluZyB0aGF0IHRoZSBvZGRzIG9mIGJlaW5nIGEgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VyIGZvciB3b21lbiBhcmUgYXJvdW5kIDAuNjUgdGltZXMgdGhlIG9kZHMgb2YgYmVpbmcgYSBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgZm9yIG1lbiwgb3IgMzUlIGxvd2VyIGZvciB3b21lbi4gVGhpcyBtYXRjaGVzIHdoYXQgd2UgY2FuIHNlZSBpbiBvdXIgZGF0YSB2aXN1YWxpemF0aW9ucyBmb3IgUXVlc3Rpb24gMi4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicGxvdDIucG5nIikpCmBgYAoKV2UgY291bGQgYWxzbyBhbnN3ZXIgdGhpcyBxdWVzdGlvbiB1c2luZyBsb2dpc3RpYyByZWdyZXNzaW9uOgoKJCRsb2cob2RkcyBcIG9mIFwgY3VycmVudCBcIGUtY2lnYXJldHRlIFwgdXNlKSA9IFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IFNleCQkCgpIZXJlIGlzIGhvdyB3ZSB3b3VsZCBmaXQgb3VyIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwsIHVzaW5nIHRoZSBgZ2xtYCBmdW5jdGlvbiBmcm9tIGJhc2UgUi4gV2UgYWxzbyB1c2UgdGhlIGB0aWR5YCBmdW5jdGlvbiBmcm9tIHRoZSBgYnJvb21gIHBhY2thZ2UgdG8gY3JlYXRlIGEgdGliYmxlIG9mIHRoZSBtb2RlbCBvdXRwdXQuCgpgYGB7cn0KZGF0MjAxNSA8LSBueXRzX2RhdGEgJT4lIAogIGZpbHRlcih5ZWFyID09IDIwMTUsICFpcy5uYShTZXgpKQoKY3VyckVjaWdTZXggPC0gZ2xtKGVjaWdfY3VycmVudCB+IFNleCwgZGF0YSA9IGRhdDIwMTUsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkKY3VyckVjaWdTZXhUaWR5IDwtIGJyb29tOjp0aWR5KGN1cnJFY2lnU2V4KQpjdXJyRWNpZ1NleFRpZHkKYGBgCgpMb29raW5nIGF0IHRoaXMgb3V0cHV0LCBvdXIgZXN0aW1hdGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZXF1YXRpb24gaXM6CgokJGxvZyhvZGRzIFwgb2YgXCBjdXJyZW50IFwgZS1jaWdhcmV0dGUgXCB1c2UpID0gXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgU2V4ID0gLTEuODkgLSAwLjQyNSBcY2RvdCAoU2V4ID09IGZlbWFsZSkkJAoKT3VyICRcYmV0YV8xJCBwYXJhbWV0ZXIgdGVsbHMgdXMgdGhhdCB0aGUgbG9nIG9kZHMgb2YgYmVpbmcgYSBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgYXJlIDAuNDI1IGxvd2VyIGZvciBmZW1hbGVzIGNvbXBhcmVkIHRvIG1hbGVzLCBpLmUuLCB0aGUgZGlmZmVyZW5jZSBpbiBsb2cgb2RkcyBvZiBiZWluZyBhIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlciBmb3IgZmVtYWxlcyBjb21wYXJlZCB0byBtYWxlcyBpcyAtMC40MjUuIEFuZCB3ZSBjYW4gbm90aWNlIHRoYXQgdGhpcyB2YWx1ZSBtYXRjaGVzIHRoZSBsb2cgb2RkcyByYXRpbyB0aGF0IHdlIGNhbGN1bGF0ZWQgYnkgaGFuZCBmcm9tIHRoZSAyeDIgdGFibGUgYWJvdmUuIFRoaXMgaXMgYmVjYXVzZSBhIGRpZmZlcmVuY2UgaW4gbG9nIG9kZHMgaXMgdGhlIHNhbWUgYXMgYSBsb2cgb2RkcyByYXRpbyAtLSByZW1lbWJlciB5b3VyIFtydWxlcyBvZiBsb2dzXShodHRwczovL3d3dy5yYXBpZHRhYmxlcy5jb20vbWF0aC9hbGdlYnJhL0xvZ2FyaXRobS5odG1sI2xvZy1ydWxlcyl7dGFyZ2V0PSJfYmxhbmsifSEKCldlIGNhbiBpbnRlcnByZXQgdGhpcyBvdXRwdXQgYXMgZm9sbG93czoKCiogJC0wLjQyNSA9IFxiZXRhXzEgPSBcbG9nKE9SKSQKKiBUaGUgbG9nIG9kZHMgb2YgYmVpbmcgYSBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgaXMgMC40MjUgbG93ZXIgZm9yIGZlbWFsZXMgY29tcGFyZWQgdG8gbWFsZXMKKiAkMC42NSA9IGVeey0wLjQyNX0gPSBlXntcYmV0YV8xfSA9IE9SJAoqIFRoZSBvZGRzIG9mIGJlaW5nIGEgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VyIGZvciBmZW1hbGVzIGlzIDAuNjUgdGltZXMgdGhlIG9kZHMgZm9yIG1hbGVzLgoqIFRoZSBvZGRzIG9mIGJlaW5nIGEgY3VycmVudCBlLWNpZ2FyZXR0ZSB1c2VyIGZvciBmZW1hbGVzIGlzIDM1JSBsb3dlciB0aGFuIHRoZSBvZGRzIGZvciBtYWxlcy4KCldlIGNhbiBhbHNvIGxvb2sgYXQgdGhlIG90aGVyIGNvbHVtbnMgb2YgdGhlIG1vZGVsIG91dHB1dCB0byBhc3Nlc3Mgd2hldGhlciBvdXIgZGF0YSBpbmRpY2F0ZSB0aGF0ICRcYmV0YV8xJCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gMC4gVGhlIHAtdmFsdWUgZm9yIHRoZSBgU2V4YCB2YXJpYWJsZSBpbiBvdXIgbW9kZWwgaXMgYHIgZm9ybWF0KGN1cnJFY2lnU2V4VGlkeSAlPiUgZmlsdGVyKHRlcm0gPT0gIlNleGZlbWFsZSIpICU+JSBwdWxsKHAudmFsdWUpLCBkaWdpdHMgPSAzKWAuIFNpbmNlIHRoaXMgdmFsdWUgaXMgPCAwLjA1LCB3ZSB3b3VsZCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0ICRcYmV0YV8xID0gMCQgYmFzZWQgb24gb3VyIG1vZGVsIG91dHB1dC4KClNpbXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIGNhbiBiZSBleHRlbmRlZCB0byBpbmNsdWRlIGFkZGl0aW9uYWwgdmFyaWFibGVzIGluIHRoZSBtb2RlbCwgZm9yIGV4YW1wbGUgdG8gYWRqdXN0IGZvciBwb3RlbnRpYWwgY29uZm91bmRpbmcgdmFyaWFibGVzIHN1Y2ggYXMgYEFnZWAgb3IgYEdyYWRlYC4gRm9yIGV4YW1wbGUsIHN1cHBvc2Ugd2Ugd2FudCB0byBlc3RpbWF0ZSB0aGUgZWZmZWN0IG9mIGBTZXhgIG9uIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlLCBob2xkaW5nIGBBZ2VgIGNvbnN0YW50LiBXZSBjb3VsZCBmaXQgdGhlIG1vZGVsOgoKJCRsb2cob2RkcyBcIG9mIFwgY3VycmVudCBcIGUtY2lnYXJldHRlIFwgdXNlKSA9IFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IFNleCArIFxiZXRhXzIgXGNkb3QgQWdlJCQKCgpgYGB7cn0KY3VyckVjaWdTZXhBZ2UgPC0gZ2xtKGVjaWdfY3VycmVudCB+IFNleCArIEFnZSwgCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0MjAxNSwgCiAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpCnRpZHkoY3VyckVjaWdTZXhBZ2UpCmBgYAoKTm93IG91ciAkXGJldGFfMSQgcGFyYW1ldGVyIHRlbGxzIHVzIHRoYXQgdGhlIGxvZyBvZGRzIG9mIGJlaW5nIGFuIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlciBhcmUgMC4zODUgbG93ZXIgZm9yIGZlbWFsZXMgY29tcGFyZWQgdG8gbWFsZXMsIHdpdGhpbiBhbiBhZ2UgZ3JvdXAsIG9yIGhvbGRpbmcgYEFnZWAgY29uc3RhbnQuCgojIyMgKipTdXJ2ZXkgd2VpZ2h0ZWQgbG9naXN0aWMgcmVncmVzc2lvbioqCioqKgoKQXMgZGlzY3Vzc2VkIGVsc2V3aGVyZSBpbiB0aGlzIGNhc2Ugc3R1ZHksIG91ciBkYXRhIGNvbWUgZnJvbSBhIHN1cnZleSwgd2hlcmUgaW5kaXZpZHVhbHMgd2VyZSBub3QgbmVjZXNzYXJpbHkgc2FtcGxlZCBpbiBkaXJlY3QgcHJvcG9ydGlvbiB0byB0aGVpciBwb3B1bGF0aW9uIHJlcHJlc2VudGF0aW9uLCBzbyBpdCBpcyBuZWNlc3NhcnkgdG8gaW5jb3Jwb3JhdGUgc3VydmV5IHdlaWdodHMgaW50byBvdXIgYW5hbHlzaXMgdG8gcGVyZm9ybSBpbmZlcmVuY2UgYWJvdXQgdGhlIHBvcHVsYXRpb24gb2YgaW50ZXJlc3QuIEx1Y2tpbHksIHRoZXJlIGFyZSBpbXBsZW1lbnRhdGlvbnMgb2Ygc3VydmV5LXdlaWdodGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaW4gUiB0aGF0IGNhbiBkbyB0aGlzIGZvciB1cy4KCldlIGZpcnN0IGNyZWF0ZSBvdXIgc3VydmV5IGRlc2lnbiBvYmplY3QgdXNpbmcgdGhlIGBhc19zdXJ2ZXlfZGVzaWduYCBmdW5jdGlvbiBmcm9tIHRoZSBgc3J2eXJgIHBhY2thZ2UsIGFuZCB0aGVuIHVzZSB0aGUgYHN2eWdsbWAgZnVuY3Rpb24gZnJvbSB0aGUgYHN1cnZleWAgcGFja2FnZSB0byBmaXQgb3VyIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwuCgpgYGB7cn0KZGF0MjAxNV9zdXJ2ZXlfZGVzaWduIDwtIGRhdDIwMTUgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfc3VydmV5X2Rlc2lnbihzdHJhdGEgPSBzdHJhdHVtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkcyA9IHBzdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgID0gZmlud2d0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5lc3QgPSBUUlVFKQoKCmN1cnJFY2lnU2V4X3N2eSA8LSBzdXJ2ZXk6OnN2eWdsbShlY2lnX2N1cnJlbnQgfiBTZXgsCiAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBxdWFzaWJpbm9taWFsKGxpbmsgPSAnbG9naXQnKSwgCiAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSBkYXQyMDE1X3N1cnZleV9kZXNpZ24pCnRpZHkoY3VyckVjaWdTZXhfc3Z5KQpgYGAKCk5vdGUgdGhhdCBpbiB0aGlzIGNhc2UsIHdlIHVzZSB0aGUgW3F1YXNpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9RdWFzaS1saWtlbGlob29kKXt0YXJnZXQ9Il9ibGFuayJ9LWJpbm9taWFsIGZhbWlseSByYXRoZXIgdGhhbiB0aGUgYmlub21pYWwgZmFtaWx5LCB3aGljaCBhbGxvd3MgdGhlIGRhdGEgdG8gbm90IG5lY2Vzc2FyaWx5IGxvb2sgbGlrZSBhIHNhbXBsZSBmcm9tIGEgW2Jpbm9taWFsIGRpc3RyaWJ1dGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQmlub21pYWxfZGlzdHJpYnV0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9LiBUaGlzIGlzIGJlY2F1c2UgYnkgaW5jb3Jwb3JhdGluZyBvdXIgc3VydmV5IHdlaWdodHMsIGl0IGlzIGFzIGlmIGVhY2ggaW5kaXZpZHVhbCBkb2VzIG5vdCBoYXZlIGEgMCBvciAxIGFzIHRoZWlyIG91dGNvbWUgdmFyaWFibGUsIHNvIHdlIGdldCBhIHdhcm5pbmcgaWYgd2UgZG8gbm90IHVzZSB0aGlzIHZhbHVlIGZvciBmYW1pbHkuCgpGcm9tIHRoaXMgbW9kZWwgb3V0cHV0LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGVzdGltYXRlIGluY29ycG9yYXRpbmcgc3VydmV5IHdlaWdodHMgaXMgYSBsaXR0bGUgZGlmZmVyZW50LiBUaGUgaW50ZXJwcmV0YXRpb24gaXMgYXMgZm9sbG93czoKCiogJC0wLjM4MyA9IFxiZXRhXzEgPSBcbG9nKE9SKSQKKiBUaGUgbG9nIG9kZHMgb2YgYmVpbmcgYSBjdXJyZW50IGUtY2lnYXJldHRlIHVzZXIgaXMgMC4zODMgbG93ZXIgZm9yIGZlbWFsZXMgdGhhbiBmb3IgbWFsZXMsIHRha2luZyBzdXJ2ZXkgd2VpZ2h0cyBpbnRvIGFjY291bnQuCiogJDAuNjggPSBlXnstMC4zODN9ID0gZV57XGJldGFfMX0gPSBPUiQKKiBUaGUgb2RkcyBvZiBiZWluZyBhIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlciBmb3IgZmVtYWxlcyBpcyAwLjY4IHRpbWVzIHRoZSBvZGRzIGZvciBtYWxlcywgdGFraW5nIHN1cnZleSB3ZWlnaHRzIGludG8gYWNjb3VudC4KKiBUaGUgb2RkcyBvZiBiZWluZyBhIGN1cnJlbnQgZS1jaWdhcmV0dGUgdXNlciBmb3IgZmVtYWxlcyBpcyAzMiUgbG93ZXIgdGhhbiB0aGUgb2RkcyBmb3IgbWFsZXMsIHRha2luZyBzdXJ2ZXkgd2VpZ2h0cyBpbnRvIGFjY291bnQuCgoKQXMgYWJvdmUsIHdlIGNhbiBhbHNvIGZpdCBhIG1vcmUgY29tcGxpY2F0ZWQgbW9kZWwgd2l0aCBhZGRpdGlvbmFsIGNvdmFyaWF0ZXMuCgpgYGB7cn0KY3VyckVjaWdTZXhBZ2Vfc3Z5IDwtIHN1cnZleTo6c3Z5Z2xtKGVjaWdfY3VycmVudCB+IFNleCArIEFnZSwKICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IHF1YXNpYmlub21pYWwobGluayA9ICdsb2dpdCcpLCAKICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IGRhdDIwMTVfc3VydmV5X2Rlc2lnbikKdGlkeShjdXJyRWNpZ1NleEFnZV9zdnkpCmBgYAoKSW4gdGhpcyBjYXNlLCB3ZSBjYW4gc2VlIHRoYXQgb3VyIGVzdGltYXRlZCBkaWZmZXJlbmNlIGluIGxvZyBvZGRzIGZvciBmZW1hbGVzIGNvbXBhcmVkIHRvIG1hbGVzLCAtMC4zODAsIGlzIG5vdCBtdWNoIGRpZmZlcmVudCB3aGV0aGVyIHdlIGFyZSBob2xkaW5nIGBBZ2VgIGNvbnN0YW50IG9yIG5vdC4KCgojIyAqKlN1bW1hcnkqKgoqKiogCgoKIyMjICoqU3VtbWFyeSBQbG90KioKKioqCgpGaW5hbGx5IHdlIHdpbGwgcHV0IG91ciBwbG90cyB0b2dldGhlciB0byBjcmVhdGUgYSBwbG90IHRoYXQgZGVzY3JpYmVzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlLWNpZ2FyZXR0ZSB1c2FnZSBhbmQgb3ZlcmFsbCB0b2JhY2NvIHVzZSwgY29tYmluaW5nIGJvdGggb3VyIGZpcnN0IHNldCBvZiB1bndlaWdodGVkIHJlc3VsdHMsIGFuZCB0aG9zZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSBgc3J2eXJgIHBhY2thZ2UuCgpgYGB7cn0KdGl0bGVfZmluYWwgPC0gZ2dkcmF3KCkgKwogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKCJXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlLWNpZ2FyZXR0ZSB1c2UgYW5kIHRvYmFjY28gdXNlPyIpLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICBzaXplID0gMTYsCiAgICB4ID0gMC41KSArCiAgdGhlbWUoCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQogICkKCnN1YnRpdGxlX3V3X2ZpbmFsIDwtIGdnZHJhdygpICsKICBkcmF3X2xhYmVsKAogICAgZXhwcmVzc2lvbih+IDZedGggfiAiLSIgfiAxMl50aCB+ICJncmFkZXJzLCB1bndlaWdodGVkIiksCiAgICBzaXplID0gMTIsCiAgICB4ID0gMC41KSArCiAgdGhlbWUoCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQogICkKCnN1YnRpdGxlX3dfZmluYWwgPC0gZ2dkcmF3KCkgKwogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKH4gNl50aCB+ICItIiB+IDEyXnRoIH4gImdyYWRlcnMsIHdlaWdodGVkIiksCiAgICBmb250ZmFjZSA9ICdib2xkJywKICAgIHNpemUgPSAxMiwKICAgIHggPSAwLjUpICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKc3VidGl0bGVfd184X2ZpbmFsIDwtIGdnZHJhdygpICsKICBkcmF3X2xhYmVsKAogICAgZXhwcmVzc2lvbigiQXBwcm94aW1hdGUgZ3JhZHVhdGluZyBcbiBjbGFzcyBvZiAyMDE5LCB3ZWlnaHRlZCIpLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICBzaXplID0gMTIsCiAgICB4ID0gMC41KSArCiAgdGhlbWUoCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQogICkKCnN1YnRpdGxlX2ZpbmFsIDwtIHBsb3RfZ3JpZChzdWJ0aXRsZV91d19maW5hbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlX3dfZmluYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0aXRsZV93XzhfZmluYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMykKCnBsb3RzQV90aXRsZV9maW5hbCA8LSBnZ2RyYXcoKSArCiAgZHJhd19sYWJlbCgKICAgIGV4cHJlc3Npb24oIlByZXZhbGVuY2Ugb2YgYW55IHRvYmFjY28gcHJvZHVjdCB1c2UgYnkgdXNlciB0eXBlIiksCiAgICBzaXplID0gMTQsCiAgICB4ID0gMC41KSArCiAgdGhlbWUoCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLCAwLCAwLCAwKQogICkKCnBsb3RzQV9maW5hbCA8LSBwbG90X2dyaWQocGxvdEFfdXcgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90QV93ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdEFfd184ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAidiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcyA9ICJidCIpCgpwbG90c0JfdGl0bGVfZmluYWwgPC0gZ2dkcmF3KCkgKwogIGRyYXdfbGFiZWwoCiAgICBleHByZXNzaW9uKCJQcmV2YWxlbmNlIG9mIGV2ZXIgdHJ5aW5nIGJ5IHByb2R1Y3QgdHlwZSIpLAogICAgc2l6ZSA9IDE0LAogICAgeCA9IDAuNSkgKwogIHRoZW1lKAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCkKICApCgpwbG90c0JfZmluYWwgPC0gcGxvdF9ncmlkKHBsb3RCX3V3ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdEJfdyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RCX3dfOCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gInYiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMgPSAiYnQiKQoKcGxvdHNDX3RpdGxlX2ZpbmFsIDwtIGdnZHJhdygpICsKICBkcmF3X2xhYmVsKAogICAgZXhwcmVzc2lvbigiUHJldmFsZW5jZSBvZiBjdXJyZW50IHVzZSBieSBwcm9kdWN0IHR5cGUiKSwKICAgIHNpemUgPSAxNCwKICAgIHggPSAwLjUpICsKICB0aGVtZSgKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApCiAgKQoKcGxvdHNDX2ZpbmFsIDwtIHBsb3RfZ3JpZChwbG90Q191dyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RDX3cgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90Q193XzggKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJ2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzID0gImJ0IikKCmxlZ2VuZF9maW5hbCA8LSBnZXRfbGVnZW5kKHBsb3QxYyArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgpmaW5hbF9wbG90IDwtIHBsb3RfZ3JpZCh0aXRsZV9maW5hbCwKICAgICAgICAgIHBsb3RzQV90aXRsZV9maW5hbCwKICAgICAgICAgIHN1YnRpdGxlX2ZpbmFsLAogICAgICAgICAgcGxvdHNBX2ZpbmFsLAogICAgICAgICAgcGxvdHNCX3RpdGxlX2ZpbmFsLAogICAgICAgICAgc3VidGl0bGVfZmluYWwsCiAgICAgICAgICBwbG90c0JfZmluYWwsCiAgICAgICAgICBwbG90c0NfdGl0bGVfZmluYWwsCiAgICAgICAgICBzdWJ0aXRsZV9maW5hbCwKICAgICAgICAgIHBsb3RzQ19maW5hbCwKICAgICAgICAgIGxlZ2VuZF9maW5hbCwKICAgICAgICAgIG5jb2wgPSAxLAogICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgMC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgIDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgICAgICAgICAgIDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAwLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAwLjEpKQoKZmluYWxfcGxvdApgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpnZ3NhdmUoaGVyZTo6aGVyZSgiaW1nIiwgImZpbmFsX3Bsb3QucG5nIikpCmBgYAoKIyMjICoqU3lub3BzaXMqKgoqKioKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2UgdXNlZCBkYXRhIGZyb20gdGhlIFtOYXRpb25hbCBZb3V0aCBUb2JhY2NvIFN1cnZleSAoTllUUyldKGh0dHBzOi8vd3d3LmNkYy5nb3YvdG9iYWNjby9kYXRhX3N0YXRpc3RpY3Mvc3VydmV5cy9ueXRzL2luZGV4Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifSwgYW4gYW5udWFsIHN1cnZleSB0aGF0IGFza3Mgc3R1ZGVudHMgaW4gaGlnaCBzY2hvb2wgYW5kIG1pZGRsZSBzY2hvb2wgKGdyYWRlcyA2LTEyKSBhYm91dCB0b2JhY2NvIHVzYWdlIGluIHRoZSBVbml0ZWQgU3RhdGVzIG9mIEFtZXJpY2EuIFdlIHVzZWQgZGF0YSBmcm9tICoqMjAxNS0yMDE5KiogZHVlIHRvIHRoZSBmYWN0IHRoYXQgdGhlc2UgeWVhcnMgYXJlIHRoZSBtb3N0IHJlY2VudCB0aGF0IGFza2VkIHF1ZXN0aW9ucyByZWdhcmRpbmcgZS1jaWdhcmV0dGUgdXNhZ2UuCgpXZSB1c2VkIHRoaXMgZGF0YSB0byBhbnN3ZXIgdGhlc2UgcXVlc3Rpb25zOgoKMSkgSG93IGhhcyB0b2JhY2NvIGFuZCBlLWNpZ2FyZXR0ZS92YXBpbmcgdXNlIGJ5IEFtZXJpY2FuIHlvdXRocyBjaGFuZ2VkIHNpbmNlIDIwMTU/CjIpIEhvdyBkb2VzIGUtY2lnYXJldHRlIHVzZSBjb21wYXJlIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXM/CjMpIFdoYXQgdmFwaW5nIGJyYW5kcyBhbmQgZmxhdm9ycyBhcHBlYXIgdG8gYmUgdXNlZCB0aGUgbW9zdCBmcmVxdWVudGx5PyAgCldlIHdpbGwgYmFzZSB0aGlzIG9uIHRoZSBmb2xsb3dpbmcgc3VydmV5IHF1ZXN0aW9uczogICAKPiAiRHVyaW5nIHRoZSBwYXN0IDMwIGRheXMsIHdoYXQgYnJhbmQgb2YgZS1jaWdhcmV0dGVzIGRpZCB5b3UgdXN1YWxseSB1c2U/IiAgIAo+ICJXaGF0IGZsYXZvcnMgb2YgdG9iYWNjbyBwcm9kdWN0cyBoYXZlIHlvdSB1c2VkIGluIHRoZSBwYXN0CjMwIGRheXM/IiAKCjQpIElzIHRoZXJlIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gZS1jaWdhcmV0dGUvdmFwaW5nIHVzZSBhbmQgb3RoZXIgdG9iYWNjbyB1c2U/CgpXZSBzaG93ZWQgaG93IHRvIHdvcmsgd2l0aCB0aGUgZGF0YSBpbiB0aGUgZm9ybWF0IHByb3ZpZGVkIChFeGNlbCksIGhvdyB0byB0byB1c2UgdGhlIGNvZGVib29rcyB0byBkZWNpZGUgd2hhdCB2YXJpYWJsZXMgdG8gdXNlIHRvIGFuc3dlciBvdXIgcXVlc3Rpb25zIGFuZCBob3cgdG8gY2xlYW4gYW5kIHJlY29kZSB0aGUgZGF0YSBmcm9tIHRoZSBzdXJ2ZXkgZm9yIG91ciB2aXN1YWxpemF0aW9ucyBhbmQgYW5hbHlzaXMuIFdlIG1hZGUgdmlzdWFsaXphdGlvbnMgb2Ygb3VyIHN1bW1hcnkgc3RhdGlzdGljcyBvdmVyIHRpbWUsIHRvIGlsbHVzdHJhdGUgdGhlIHRyZW5kcyBwcmVzZW50IGluIHRoZSBkYXRhIGZvciBkaWZmZXJlbnQgcHJvZHVjdHMgYW5kIGdyb3VwcyBvZiBzdHVkZW50IHJlc3BvbmRlbnRzLgoKSW4gYW5zd2VyIHRvIG91ciBxdWVzdGlvbnMsIHdlIGZvdW5kIHRoYXQgdG9iYWNjbyB1c2UgaGFzIGdvbmUgdXAgc2xpZ2h0bHkgb3ZlcmFsbCBiZXR3ZWVuIDIwMTUgYW5kIDIwMTksIHdpdGggbGl0dGxlIGRpZmZlcmVuY2UgaW4gcmF0ZXMgb2YgY2hhbmdlIGNvbXBhcmluZyBtYWxlcyB0byBmZW1hbGVzLiBUaGlzIHNsaWdodCBpbmNyZWFzZSBpcyB0aGUgcmVzdWx0IG9mIGEgbGFyZ2UgaW5jcmVhc2UgaW4gZS1jaWdhcmV0dGUvdmFwaW5nIHVzZSwgY291cGxlZCB3aXRoIGEgZGVjcmVhc2UgaW4gdXNlIG9mIG90aGVyIHRvYmFjY28gcHJvZHVjdHMuIFRoZSBtb3N0IHVzZWQgYnJhbmQgb2YgZS1jaWdhcmV0dGUvdmFwaW5nIHByb2R1Y3RzIGlzIEp1dWwsIGFuZCBmcnVpdCwgbWVudGhvbCBhbmQgY2FuZHkvZGVzc2VydHMvc3dlZXRzIGFyZSB0aGUgbW9zdCBjb21tb25seSB1c2VkIGZsYXZvcnMuCgpXZSB0aGVuIGludHJvZHVjZWQgdGhlIHN0YXRpc3RpY2FsIGNvbmNlcHQgb2Ygc3VydmV5IHdlaWdodGluZywgaWxsdXN0cmF0aW5nIGhvdyB0byBjYWxjdWxhdGUgdXNhZ2UgcGVyY2VudGFnZXMgdXNpbmcgc3VydmV5LXdlaWdodGVkIG1lYW5zLCBhbmQgY29tcGFyZSB0aGUgcmVzdWx0cyBpbiB0aGUgd2VpZ2h0ZWQgYW5kIHVud2VpZ2h0ZWQgY2FzZXMuIFdlIGFsc28gaW50cm9kdWNlZCB0aGUgdG9waWMgb2YgbG9naXN0aWMgcmVncmVzc2lvbiBhbmQgd2UgcGVyZm9ybWVkIGEgc3VydmV5LXdlaWdodGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24gYW5hbHlzaXMgdG8gY29tcGFyZSB0aGUgdmFwaW5nIHJhdGVzIG9mIG1hbGUgYW5kIGZlbWFsZSBzdHVkZW50cy4gCgojIyAqKkhvbWV3b3JrKioKKioqIAoKPHN0eWxlPgpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I2U2ZjBmZjsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30KPC9zdHlsZT4KPGRpdiBjbGFzcyA9ICJibHVlIj4KCisgQ2FsY3VsYXRlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZvciB0aGUgdW53ZWlnaHRlZCBlc3RpbWF0ZXMgYW5kIGFkZCB0aGUgYXBwcm9wcmlhdGUgZXJyb3IgYmFycyB0byB0aGUgbWFpbiBmaWd1cmVzLgorIEFwcGx5IHN1cnZleSB3ZWlnaHRzIHRvIG9uZSBvZiB0aGUgZmlndXJlcyBwcm9kdWNlZCBpbiB0aGlzIGNhc2Ugc3R1ZHkgaW4gd2hpY2ggd2VpZ2h0ZWQgZXN0aW1hdGVzIHdlcmUgbm90IHByb2R1Y2VkLiBJbmNsdWRlIGVycm9yIGJhcnMgaW4gdGhlIHVwZGF0ZWQgZmlndXJlLgogICAgKyBEb2VzIHRoZSBmaWd1cmUgY2hhbmdlIGFmdGVyIHRoZSBhcHBsaWNhdGlvbiBvZiBzdXJ2ZXkgd2VpZ2h0cz8KICAgICsgSWYgc28sIGRlc2NyaWJlIGhvdy4gCisgUmVwcm9kdWNlIGBmaW5hbF9wbG90YCBhYm92ZSBmb3IgYSBkaWZmZXJlbnQgY29ob3J0IG9mIHlvdXIgY2hvaWNlLgorIEZvY3VzaW5nIG9uIGEgc2luZ2xlIHllYXIgb2YgZGF0YSwgZXhwbG9yZSBkZW1vZ3JhcGhpYyBmYWN0b3JzIHRoYXQgY29udHJpYnV0ZSB0byB0b2JhY2NvIHVzZSBvZiBzb21lIGtpbmQuIENvbXBhcmUgcmVzdWx0cyBvZiB1bndlaWdodGVkIGFuZCB3ZWlnaHRlZCBhbmFseXNpcyAoZm9yIGV4YW1wbGUsIHVzaW5nIHRoZSBgc3Z5Z2xtYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgc3VydmV5LXdlaWdodGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZXN0aW1hdGVzKS4KCjwvZGl2PgoKCiMjICoqQWRkaXRpb25hbCBJbmZvcm1hdGlvbioqCioqKiAKCiMjIyAqKkhlbHBmdWwgTGlua3MqKgoqKioKCltUaWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1dyaXRpbmcgZnVuY3Rpb25zXShodHRwczovL3I0ZHMuaGFkLmNvLm56L2Z1bmN0aW9ucy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgCltDb2RlYm9va3NdKGh0dHBzOi8vd3d3LmxpYi5uY3N1LmVkdS9kYXRhL2ljcHNyZmFxI3doYXRhcmUpe3RhcmdldD0iX2JsYW5rIn0gIApbTG9uZ2l0dWRpbmFsIHN0dWRpZXNdKGh0dHBzOi8vd3d3LmJtai5jb20vYWJvdXQtYm1qL3Jlc291cmNlcy1yZWFkZXJzL3B1YmxpY2F0aW9ucy9lcGlkZW1pb2xvZ3ktdW5pbml0aWF0ZWQvNy1sb25naXR1ZGluYWwtc3R1ZGllcyl7dGFyZ2V0PSJfYmxhbmsifSAgIApbUGFuZWwgZGF0YV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGFuZWxfZGF0YSl7dGFyZ2V0PSJfYmxhbmsifSAgICAKW0Nyb3NzLXNlY3Rpb25hbCBkYXRhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy1zZWN0aW9uYWxfZGF0YSl7dGFyZ2V0PSJfYmxhbmsifSAgICAKW1N1cnZleSB3ZWlnaHRpbmddKGh0dHA6Ly93d3cuYXBwbGllZC1zdXJ2ZXktbWV0aG9kcy5jb20vd2VpZ2h0Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIApbQ29uZmlkZW5jZSBpbnRlcnZhbHNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NvbmZpZGVuY2VfaW50ZXJ2YWwpe3RhcmdldD0iX2JsYW5rIn0gICAKW0ludHJvZHVjdGlvbiB0byBMb2dhcml0aG1zXShodHRwczovL3d3dy5tYXRoc2lzZnVuLmNvbS9hbGdlYnJhL2xvZ2FyaXRobXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgIApbTG9nYXJpdGhtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb2dhcml0aG0pe3RhcmdldD0iX2JsYW5rIn0gCltSdWxlcyBvZiBsb2dzXShodHRwczovL3d3dy5yYXBpZHRhYmxlcy5jb20vbWF0aC9hbGdlYnJhL0xvZ2FyaXRobS5odG1sI2xvZy1ydWxlcyl7dGFyZ2V0PSJfYmxhbmsifSBbT2RkcyByYXRpb10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT2Rkc19yYXRpbyl7dGFyZ2V0PSJfYmxhbmsifSAgICAKW0xvZyBvZGRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb2dpdCl7dGFyZ2V0PSJfYmxhbmsifSAgIApbMngyIHRhYmxlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db250aW5nZW5jeV90YWJsZSl7dGFyZ2V0PSJfYmxhbmsifSAgCltQcm9iYWJpbGl0eV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUHJvYmFiaWxpdHkpe3RhcmdldD0iX2JsYW5rIn0gICAKW0xpa2VsaWhvb2QgZnVuY3Rpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xpa2VsaWhvb2RfZnVuY3Rpb24pe3RhcmdldD0iX2JsYW5rIn0gICAKW01heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01heGltdW1fbGlrZWxpaG9vZF9lc3RpbWF0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAgCltMaW5lYXIgcmVncmVzc2lvbiBtb2RlbF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGluZWFyX3JlZ3Jlc3Npb24pe3RhcmdldD0iX2JsYW5rIn0gICAKW0xvZ2lzdGljIHJlZ3Jlc3Npb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xvZ2lzdGljX3JlZ3Jlc3Npb24pe3RhcmdldD0iX2JsYW5rIn0gICAKW1F1YXNpLWxpa2VsaWhvb2RdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1F1YXNpLWxpa2VsaWhvb2Qpe3RhcmdldD0iX2JsYW5rIn0gICAKW0Jpbm9taWFsIGRpc3RyaWJ1dGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQmlub21pYWxfZGlzdHJpYnV0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAgCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBsaW5lYXIgcmVncmVzc2lvbiBzZWUgdGhpcyBbYm9va10oaHR0cHM6Ly9yYWZhbGFiLmdpdGh1Yi5pby9kc2Jvb2svbGluZWFyLW1vZGVscy5odG1sI2xpbmVhci1yZWdyZXNzaW9uLWluLXRoZS10aWR5dmVyc2Upe3RhcmdldD0iX2JsYW5rIn0gYW5kIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtZGlldC8pe3RhcmdldD0iX2JsYW5rIn0uCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBzdXJ2ZXkgZGVzaWducyBzZWUgW2hlcmVdKGh0dHA6Ly93d3cuYXNhc3Jtcy5vcmcvUHJvY2VlZGluZ3MveTIwMDgvRmlsZXMvMzAxODM1LnBkZil7dGFyZ2V0PSJfYmxhbmsifSBhbmQgW2hlcmVdKGh0dHA6Ly9vY3cuamhzcGguZWR1L2NvdXJzZXMvU3RhdE1ldGhvZHNGb3JTYW1wbGVTdXJ2ZXlzL1BERnMvTGVjdHVyZTUucGRmKXt0YXJnZXQ9Il9ibGFuayJ9LiAgCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBzdXJ2ZXkgYW5hbHlzaXMgaW4gUiBbaGVyZV0oaHR0cHM6Ly9yLXN1cnZleS5yLWZvcmdlLnItcHJvamVjdC5vcmcvc3VydmV5L2V4bWFtcGxlLWxvbmVseS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBbaGVyZV0oaHR0cDovL3Itc3VydmV5LnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9zdXJ2ZXkvaHRtbC9zdXJ2ZXlvcHRpb25zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uICAgCgpJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gYW4gaW5mby1ncmFwaGljIHN1bW1hcnkgb2YgdGhlIDIwMTkgZmluZGluZ3MsIGFuZCBsaW5rcyB0byBtYW55IG1vcmUgcmVzb3VyY2VzIGFib3V0IHRoaXMgdG9waWMgYW5kIGRhdGEgc2V0LCBzZWUgdGhlIEZEQSdzIHdlYnNpdGUgW2hlcmVdKGh0dHBzOi8vd3d3LmZkYS5nb3YvdG9iYWNjby1wcm9kdWN0cy95b3V0aC1hbmQtdG9iYWNjby95b3V0aC10b2JhY2NvLXVzZS1yZXN1bHRzLW5hdGlvbmFsLXlvdXRoLXRvYmFjY28tc3VydmV5KXt0YXJnZXQ9Il9ibGFuayJ9LgoKPHU+KipQYWNrYWdlcyB1c2VkIGluIHRoaXMgY2FzZSBzdHVkeToqKjwvdT4KClBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhICAKW3JlYWR4bF0oaHR0cHM6Ly9yZWFkeGwudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGltcG9ydCB0aGUgZGF0YSBpbiB0aGUgZXhjZWwgZmlsZXMgClttYWdyaXR0cl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gdXNlIHRoZSBjb21wb3VuZCBhc3NpZ25tZW50IHBpcGUgb3BlcmF0b3IgYCU8PiVgCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYW5pcHVsYXRlIHRoZSBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEgIApbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIGltcG9ydCB0aGUgZGF0YSBpbiBhbGwgdGhlIGRpZmZlcmVudCBleGNlbCBhbmQgY3N2IGZpbGVzIGVmZmljaWVudGx5CltkcGx5cl0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gYXJyYW5nZS9maWx0ZXIvc2VsZWN0L2NvbXBhcmUgc3BlY2lmaWMgc3Vic2V0cyBvZiB0aGUgZGF0YSAgCltyZWFkcl0oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gaW1wb3J0IHRoZSBDU1YgZmlsZSBkYXRhClt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gcmVhcnJhbmdlIGRhdGEgaW4gd2lkZSBhbmQgbG9uZyBmb3JtYXRzIApbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFrZSB2aXN1YWxpemF0aW9ucyB3aXRoIG11bHRpcGxlIGxheWVycwpbc2NhbGVzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc2NhbGVzL3NjYWxlcy5wZGYpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBhbGxvdyB1cyB0byBsb29rIGF0IHRoZSBjb2xvcnMgd2l0aGluIHRoZSB2aXJpZGlzIHBhY2thZ2UKW3ZpcmlkaXNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy92aXJpZGlzL3ZpZ25ldHRlcy9pbnRyby10by12aXJpZGlzLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYWtlIHBsb3RzIHdpdGggYSBjb2xvciBwYWxldHRlIHRoYXQgaXMgY29tcGF0aWJsZSB3aXRoIGNvbG9yIGJsaW5kbmVzcwpbZm9yY2F0c10oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gYWxsb3cgZm9yIHJlb3JkZXJpbmcgb2YgZmFjdG9ycyBpbiBwbG90cwpbbmFuaWFyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbmFuaWFyL3ZpZ25ldHRlcy9nZXR0aW5nLXN0YXJ0ZWQtdy1uYW5pYXIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgfCB0byBtYWtlIGEgdmlzdWFsaXphdGlvbiBvZiBtaXNzaW5nIGRhdGEKW3N5cnZyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc3J2eXIvc3J2eXIucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gdXNlIHN1cnZleSB3ZWlnaHRzCltjb3dwbG90XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY293cGxvdC92aWduZXR0ZXMvaW50cm9kdWN0aW9uLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBhbGxvdyBwbG90cyB0byBiZSBjb21iaW5lZCAKW2Jyb29tXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvYnJvb20vdmlnbmV0dGVzL2Jyb29tLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBjcmVhdGUgbmljZWx5IGZvcm1hdHRlZCBtb2RlbCBvdXRwdXQKW3N1cnZleV0oaHR0cDovL3Itc3VydmV5LnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9zdXJ2ZXkvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGZpdCBzdXJ2ZXktd2VpZ2h0ZWQgbG9naXN0aWMgcmVncmVzc2lvbgoKIyMjICoqU2Vzc2lvbiBpbmZvKioKKioqCgoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgojIyMgKipBY2tub3dsZWRnZW1lbnRzKioKKioqCgpXZSB3b3VsZCBsaWtlIHRvIGFja25vd2xlZGdlIFtSZW5lZSBKb2huc29uXShodHRwczovL3d3dy5qaHNwaC5lZHUvZmFjdWx0eS9kaXJlY3RvcnkvcHJvZmlsZS8yODQ4L3JlbmVlLW0tam9obnNvbikgZm9yIGFzc2lzdGluZyBpbiBmcmFtaW5nIHRoZSBtYWpvciBkaXJlY3Rpb24gb2YgdGhlIGNhc2Ugc3R1ZHkgYW5kIGZvciByZXZpZXdpbmcgdGhlIGNhc2Ugc3R1ZHkgZm9yIHN1YmplY3QgbWF0dGVyIGNvbnRlbnQuCgpXZSB3b3VsZCBhbHNvIGxpa2UgdG8gYWNrbm93bGVkZ2UgdGhlIFtCbG9vbWJlcmcgQW1lcmljYW4gSGVhbHRoIEluaXRpYXRpdmVdKGh0dHBzOi8vYW1lcmljYW5oZWFsdGguamh1LmVkdS8pIGZvciBmdW5kaW5nIHRoaXMgd29yay4gCg==